{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "79d9aaef",
   "metadata": {},
   "source": [
    "# Working with Market Depth and Trades"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0585554",
   "metadata": {},
   "source": [
    "## Display 3-depth"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8bbb4d6f-7a84-4fec-ac56-24a3d2b3d78a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from numba import njit\n",
    "\n",
    "@njit\n",
    "def print_3depth(hbt):\n",
    "    while hbt.elapse(60_000_000_000) == 0:\n",
    "        print('current_timestamp:', hbt.current_timestamp)\n",
    "\n",
    "        # Gets the market depth for the first asset, in the same order as when you created the backtest.\n",
    "        depth = hbt.depth(0)\n",
    "\n",
    "        # a key of bid_depth or ask_depth is price in ticks.\n",
    "        # (integer) price_tick = rice / tick_size\n",
    "        i = 0\n",
    "        for price_tick in range(depth.best_ask_tick, depth.best_ask_tick + 100):\n",
    "            qty = depth.ask_qty_at_tick(price_tick)\n",
    "            if qty > 0:\n",
    "                print(\n",
    "                    'ask: ',\n",
    "                    qty,\n",
    "                    '@',\n",
    "                    np.round(price_tick * depth.tick_size, 1)\n",
    "                )\n",
    "                \n",
    "                i += 1\n",
    "                if i == 3:\n",
    "                    break\n",
    "        i = 0\n",
    "        for price_tick in range(depth.best_bid_tick, max(depth.best_bid_tick - 100, 0), -1):\n",
    "            qty = depth.bid_qty_at_tick(price_tick)\n",
    "            if qty > 0:\n",
    "                print(\n",
    "                    'bid: ',\n",
    "                    qty,\n",
    "                    '@',\n",
    "                    np.round(price_tick * depth.tick_size, 1)\n",
    "                )\n",
    "            \n",
    "                i += 1\n",
    "                if i == 3:\n",
    "                    break\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0aab2f88",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "btcusdt_20240809 = np.load('usdm/btcusdt_20240809.npz')['data']\n",
    "btcusdt_20240808_eod = np.load('usdm/btcusdt_20240808_eod.npz')['data']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "79afc7c0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "current_timestamp: 1723161661500000000\n",
      "ask:  1.759 @ 61594.2\n",
      "ask:  0.006 @ 61594.4\n",
      "ask:  0.114 @ 61595.2\n",
      "bid:  3.526 @ 61594.1\n",
      "bid:  0.016 @ 61594.0\n",
      "bid:  0.002 @ 61593.9\n",
      "current_timestamp: 1723161721500000000\n",
      "ask:  2.575 @ 61576.6\n",
      "ask:  0.004 @ 61576.7\n",
      "ask:  0.455 @ 61577.0\n",
      "bid:  2.558 @ 61576.5\n",
      "bid:  0.002 @ 61576.0\n",
      "bid:  0.515 @ 61575.5\n",
      "current_timestamp: 1723161781500000000\n",
      "ask:  0.131 @ 61629.7\n",
      "ask:  0.005 @ 61630.1\n",
      "ask:  0.005 @ 61630.5\n",
      "bid:  5.742 @ 61629.6\n",
      "bid:  0.247 @ 61629.4\n",
      "bid:  0.034 @ 61629.3\n",
      "current_timestamp: 1723161841500000000\n",
      "ask:  0.202 @ 61621.6\n",
      "ask:  0.002 @ 61622.5\n",
      "ask:  0.003 @ 61622.6\n",
      "bid:  3.488 @ 61621.5\n",
      "bid:  0.86 @ 61620.0\n",
      "bid:  0.248 @ 61619.6\n",
      "current_timestamp: 1723161901500000000\n",
      "ask:  1.397 @ 61584.0\n",
      "ask:  0.832 @ 61585.1\n",
      "ask:  0.132 @ 61586.0\n",
      "bid:  3.307 @ 61583.9\n",
      "bid:  0.01 @ 61583.8\n",
      "bid:  0.002 @ 61582.0\n"
     ]
    }
   ],
   "source": [
    "from hftbacktest import BacktestAsset, HashMapMarketDepthBacktest\n",
    "\n",
    "asset = (\n",
    "    BacktestAsset()\n",
    "        .data(btcusdt_20240809)\n",
    "        .initial_snapshot(btcusdt_20240808_eod)\n",
    "        .linear_asset(1.0) \n",
    "        .constant_latency(10_000_000, 10_000_000)\n",
    "        .risk_adverse_queue_model() \n",
    "        .no_partial_fill_exchange()\n",
    "        .trading_value_fee_model(0.0002, 0.0007)\n",
    "        .tick_size(0.1)\n",
    "        .lot_size(0.001)\n",
    ")\n",
    "\n",
    "hbt = HashMapMarketDepthBacktest([asset])\n",
    "\n",
    "print_3depth(hbt)\n",
    "\n",
    "_ = hbt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "354e8fec-95cb-4205-b820-f934fa2d5836",
   "metadata": {},
   "source": [
    "## Efficient Market Depth Access\n",
    "\n",
    "`ROIVectorMarketDepth` provides more efficient market depth access through a vector that holds a limited price range of interest. The backtester using this feature can be created by `ROIVectorMarketDepthBacktest`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "580a566c-6520-40b0-90ec-c2a933017b52",
   "metadata": {},
   "outputs": [],
   "source": [
    "from numba import njit\n",
    "\n",
    "@njit\n",
    "def print_3depth_fast(hbt):\n",
    "    roi_lb_tick = int(round(30000 / 0.1))\n",
    "    roi_ub_tick = int(round(90000 / 0.1))\n",
    "    \n",
    "    while hbt.elapse(60_000_000_000) == 0:\n",
    "        print('current_timestamp:', hbt.current_timestamp)\n",
    "\n",
    "        # Gets the market depth for the first asset, in the same order as when you created the backtest.\n",
    "        depth = hbt.depth(0)\n",
    "\n",
    "        # a key of bid_depth or ask_depth is price in ticks.\n",
    "        # (integer) price_tick = price / tick_size\n",
    "        i = 0\n",
    "        # for price_tick in range(depth.best_ask_tick, depth.best_ask_tick + 100):\n",
    "        #     # depth.ask_depth returns the ask depth array, whose length is (roi_ub_tick + 1 - roi_lb_tick),\n",
    "        #     # containing the quantities ranging from roi_lb_tick to roi_ub_tick.\n",
    "        #     # Checks that the price_tick is in that range and adjust the index by subtracting roi_lb_tick.\n",
    "        #     if price_tick < roi_lb_tick or price_tick > roi_ub_tick:\n",
    "        #         continue\n",
    "        #     t = price_tick - roi_lb_tick\n",
    "        #     qty = depth.ask_depth[t]\n",
    "        #     if qty > 0:\n",
    "        #         print(\n",
    "        #             'ask: ',\n",
    "        #             qty,\n",
    "        #             '@',\n",
    "        #             np.round(price_tick * depth.tick_size, 1)\n",
    "        #         )\n",
    "                \n",
    "        #         i += 1\n",
    "        #         if i == 3:\n",
    "        #             break\n",
    "        # i = 0\n",
    "        # for price_tick in range(depth.best_bid_tick, max(depth.best_bid_tick - 100, 0), -1):\n",
    "        #     # depth.bid_depth returns the bid depth array, whose length is (roi_ub_tick + 1 - roi_lb_tick),\n",
    "        #     # containing the quantities ranging from roi_lb_tick to roi_ub_tick.\n",
    "        #     # Checks that the price_tick is in that range and adjust the index by subtracting roi_lb_tick.\n",
    "        #     if price_tick < roi_lb_tick or price_tick > roi_ub_tick:\n",
    "        #         continue\n",
    "        #     t = price_tick - roi_lb_tick\n",
    "        #     qty = depth.bid_depth[t]\n",
    "        #     if qty > 0:\n",
    "        #         print(\n",
    "        #             'bid: ',\n",
    "        #             qty,\n",
    "        #             '@',\n",
    "        #             np.round(price_tick * depth.tick_size, 1)\n",
    "        #         )\n",
    "            \n",
    "        #         i += 1\n",
    "        #         if i == 3:\n",
    "        #             break\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "94d2e7a7-9179-4380-8e18-661833a4b95f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from hftbacktest import ROIVectorMarketDepthBacktest\n",
    "\n",
    "asset = (\n",
    "    BacktestAsset()\n",
    "        .data(btcusdt_20240809)\n",
    "        .initial_snapshot(btcusdt_20240808_eod)\n",
    "        .linear_asset(1.0) \n",
    "        .constant_latency(10_000_000, 10_000_000)\n",
    "        .risk_adverse_queue_model() \n",
    "        .no_partial_fill_exchange()\n",
    "        .trading_value_fee_model(0.0002, 0.0007)\n",
    "        .tick_size(0.1)\n",
    "        .lot_size(0.001)\n",
    "        # Sets the lower bound price for the range of interest in the market depth.\n",
    "        .roi_lb(30000)\n",
    "        # Sets the upper bound price for the range of interest in the market depth.\n",
    "        .roi_ub(90000)\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a8e2b8bc-eb4f-4401-9d1c-d4e5428708e4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "current_timestamp: 1723161661500000000\n",
      "current_timestamp: 1723161721500000000\n",
      "current_timestamp: 1723161781500000000\n",
      "current_timestamp: 1723161841500000000\n",
      "current_timestamp: 1723161901500000000\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hbt = ROIVectorMarketDepthBacktest([asset])\n",
    "\n",
    "print_3depth_fast(hbt)\n",
    "\n",
    "#_ = hbt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8f00571",
   "metadata": {},
   "source": [
    "## Order Book Imbalance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e8d55680",
   "metadata": {},
   "outputs": [],
   "source": [
    "@njit\n",
    "def orderbookimbalance(hbt, out):\n",
    "    roi_lb_tick = int(round(30000 / 0.1))\n",
    "    roi_ub_tick = int(round(90000 / 0.1))\n",
    "\n",
    "    while hbt.elapse(10 * 1e9) == 0:\n",
    "        depth = hbt.depth(0)\n",
    "        \n",
    "        mid_price = (depth.best_bid + depth.best_ask) / 2.0\n",
    "        \n",
    "        sum_ask_qty_50bp = 0.0\n",
    "        sum_ask_qty = 0.0\n",
    "        for price_tick in range(depth.best_ask_tick, roi_ub_tick + 1):\n",
    "            if price_tick < roi_lb_tick or price_tick > roi_ub_tick:\n",
    "                continue\n",
    "            t = price_tick - roi_lb_tick\n",
    "            \n",
    "            ask_price = price_tick * depth.tick_size\n",
    "            depth_from_mid = (ask_price - mid_price) / mid_price\n",
    "            if depth_from_mid > 0.01:\n",
    "                break\n",
    "            sum_ask_qty += depth.ask_depth[t]\n",
    "            \n",
    "            if depth_from_mid <= 0.005:\n",
    "                sum_ask_qty_50bp = sum_ask_qty\n",
    "                \n",
    "                \n",
    "        sum_bid_qty_50bp = 0.0\n",
    "        sum_bid_qty = 0.0\n",
    "        for price_tick in range(depth.best_bid_tick, roi_lb_tick - 1, -1):\n",
    "            if price_tick < roi_lb_tick or price_tick > roi_ub_tick:\n",
    "                continue\n",
    "            t = price_tick - roi_lb_tick\n",
    "            \n",
    "            bid_price = price_tick * depth.tick_size\n",
    "            depth_from_mid = (mid_price - bid_price) / mid_price\n",
    "            if depth_from_mid > 0.01:\n",
    "                break\n",
    "            sum_bid_qty += depth.bid_depth[t]\n",
    "            \n",
    "            if depth_from_mid <= 0.005:\n",
    "                sum_bid_qty_50bp = sum_bid_qty\n",
    "                \n",
    "        imbalance_50bp = sum_bid_qty_50bp - sum_ask_qty_50bp\n",
    "        imbalance_1pct = sum_bid_qty - sum_ask_qty\n",
    "        imbalance_tob = depth.bid_depth[depth.best_bid_tick - roi_lb_tick] - depth.ask_depth[depth.best_ask_tick - roi_lb_tick]\n",
    "        \n",
    "        out.append((hbt.current_timestamp, imbalance_tob, imbalance_50bp, imbalance_1pct))        \n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "99a684f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from numba.typed import List\n",
    "from numba.types import Tuple, float64\n",
    "\n",
    "hbt = ROIVectorMarketDepthBacktest([asset])\n",
    "\n",
    "tup_ty = Tuple((float64, float64, float64, float64))\n",
    "out = List.empty_list(tup_ty, allocated=100_000)\n",
    "\n",
    "orderbookimbalance(hbt, out)\n",
    "\n",
    "_ = hbt.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "be1b53b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (30, 4)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Local Timestamp</th><th>TOB Imbalance</th><th>0.5% Imbalance</th><th>1% Imbalance</th></tr><tr><td>datetime[ns]</td><td>f64</td><td>f64</td><td>f64</td></tr></thead><tbody><tr><td>2024-08-09 00:00:11.500</td><td>2.729</td><td>-1748.101</td><td>-3908.736</td></tr><tr><td>2024-08-09 00:00:21.500</td><td>4.623</td><td>-1749.435</td><td>-3512.845</td></tr><tr><td>2024-08-09 00:00:31.500</td><td>-6.465</td><td>-1259.897</td><td>-3357.755</td></tr><tr><td>2024-08-09 00:00:41.500</td><td>-7.922</td><td>-1174.185</td><td>-3471.955</td></tr><tr><td>2024-08-09 00:00:51.500</td><td>-2.484</td><td>-1147.597</td><td>-3461.48</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>2024-08-09 00:04:21.500</td><td>3.828</td><td>-1186.236</td><td>-3551.78</td></tr><tr><td>2024-08-09 00:04:31.500</td><td>-1.35</td><td>-1332.379</td><td>-3517.854</td></tr><tr><td>2024-08-09 00:04:41.500</td><td>-3.754</td><td>-1166.521</td><td>-2693.672</td></tr><tr><td>2024-08-09 00:04:51.500</td><td>-2.525</td><td>-1188.56</td><td>-2716.914</td></tr><tr><td>2024-08-09 00:05:01.500</td><td>1.91</td><td>-594.991</td><td>-2138.82</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "shape: (30, 4)\n",
       "┌─────────────────────────┬───────────────┬────────────────┬──────────────┐\n",
       "│ Local Timestamp         ┆ TOB Imbalance ┆ 0.5% Imbalance ┆ 1% Imbalance │\n",
       "│ ---                     ┆ ---           ┆ ---            ┆ ---          │\n",
       "│ datetime[ns]            ┆ f64           ┆ f64            ┆ f64          │\n",
       "╞═════════════════════════╪═══════════════╪════════════════╪══════════════╡\n",
       "│ 2024-08-09 00:00:11.500 ┆ 2.729         ┆ -1748.101      ┆ -3908.736    │\n",
       "│ 2024-08-09 00:00:21.500 ┆ 4.623         ┆ -1749.435      ┆ -3512.845    │\n",
       "│ 2024-08-09 00:00:31.500 ┆ -6.465        ┆ -1259.897      ┆ -3357.755    │\n",
       "│ 2024-08-09 00:00:41.500 ┆ -7.922        ┆ -1174.185      ┆ -3471.955    │\n",
       "│ 2024-08-09 00:00:51.500 ┆ -2.484        ┆ -1147.597      ┆ -3461.48     │\n",
       "│ …                       ┆ …             ┆ …              ┆ …            │\n",
       "│ 2024-08-09 00:04:21.500 ┆ 3.828         ┆ -1186.236      ┆ -3551.78     │\n",
       "│ 2024-08-09 00:04:31.500 ┆ -1.35         ┆ -1332.379      ┆ -3517.854    │\n",
       "│ 2024-08-09 00:04:41.500 ┆ -3.754        ┆ -1166.521      ┆ -2693.672    │\n",
       "│ 2024-08-09 00:04:51.500 ┆ -2.525        ┆ -1188.56       ┆ -2716.914    │\n",
       "│ 2024-08-09 00:05:01.500 ┆ 1.91          ┆ -594.991       ┆ -2138.82     │\n",
       "└─────────────────────────┴───────────────┴────────────────┴──────────────┘"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import polars as pl\n",
    "\n",
    "df = pl.DataFrame(out).transpose()\n",
    "df.columns = ['Local Timestamp', 'TOB Imbalance', '0.5% Imbalance', '1% Imbalance']\n",
    "df = df.with_columns(\n",
    "    pl.from_epoch('Local Timestamp', time_unit='ns')\n",
    ")\n",
    "\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f3b43c9f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "(function(root) {\n",
       "  function now() {\n",
       "    return new Date();\n",
       "  }\n",
       "\n",
       "  var force = true;\n",
       "  var py_version = '3.4.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n",
       "  var reloading = false;\n",
       "  var Bokeh = root.Bokeh;\n",
       "\n",
       "  if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n",
       "    root._bokeh_timeout = Date.now() + 5000;\n",
       "    root._bokeh_failed_load = false;\n",
       "  }\n",
       "\n",
       "  function run_callbacks() {\n",
       "    try {\n",
       "      root._bokeh_onload_callbacks.forEach(function(callback) {\n",
       "        if (callback != null)\n",
       "          callback();\n",
       "      });\n",
       "    } finally {\n",
       "      delete root._bokeh_onload_callbacks;\n",
       "    }\n",
       "    console.debug(\"Bokeh: all callbacks have finished\");\n",
       "  }\n",
       "\n",
       "  function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n",
       "    if (css_urls == null) css_urls = [];\n",
       "    if (js_urls == null) js_urls = [];\n",
       "    if (js_modules == null) js_modules = [];\n",
       "    if (js_exports == null) js_exports = {};\n",
       "\n",
       "    root._bokeh_onload_callbacks.push(callback);\n",
       "\n",
       "    if (root._bokeh_is_loading > 0) {\n",
       "      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n",
       "      return null;\n",
       "    }\n",
       "    if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n",
       "      run_callbacks();\n",
       "      return null;\n",
       "    }\n",
       "    if (!reloading) {\n",
       "      console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n",
       "    }\n",
       "\n",
       "    function on_load() {\n",
       "      root._bokeh_is_loading--;\n",
       "      if (root._bokeh_is_loading === 0) {\n",
       "        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n",
       "        run_callbacks()\n",
       "      }\n",
       "    }\n",
       "    window._bokeh_on_load = on_load\n",
       "\n",
       "    function on_error() {\n",
       "      console.error(\"failed to load \" + url);\n",
       "    }\n",
       "\n",
       "    var skip = [];\n",
       "    if (window.requirejs) {\n",
       "      window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n",
       "      root._bokeh_is_loading = css_urls.length + 0;\n",
       "    } else {\n",
       "      root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n",
       "    }\n",
       "\n",
       "    var existing_stylesheets = []\n",
       "    var links = document.getElementsByTagName('link')\n",
       "    for (var i = 0; i < links.length; i++) {\n",
       "      var link = links[i]\n",
       "      if (link.href != null) {\n",
       "\texisting_stylesheets.push(link.href)\n",
       "      }\n",
       "    }\n",
       "    for (var i = 0; i < css_urls.length; i++) {\n",
       "      var url = css_urls[i];\n",
       "      if (existing_stylesheets.indexOf(url) !== -1) {\n",
       "\ton_load()\n",
       "\tcontinue;\n",
       "      }\n",
       "      const element = document.createElement(\"link\");\n",
       "      element.onload = on_load;\n",
       "      element.onerror = on_error;\n",
       "      element.rel = \"stylesheet\";\n",
       "      element.type = \"text/css\";\n",
       "      element.href = url;\n",
       "      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n",
       "      document.body.appendChild(element);\n",
       "    }    var existing_scripts = []\n",
       "    var scripts = document.getElementsByTagName('script')\n",
       "    for (var i = 0; i < scripts.length; i++) {\n",
       "      var script = scripts[i]\n",
       "      if (script.src != null) {\n",
       "\texisting_scripts.push(script.src)\n",
       "      }\n",
       "    }\n",
       "    for (var i = 0; i < js_urls.length; i++) {\n",
       "      var url = js_urls[i];\n",
       "      if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n",
       "\tif (!window.requirejs) {\n",
       "\t  on_load();\n",
       "\t}\n",
       "\tcontinue;\n",
       "      }\n",
       "      var element = document.createElement('script');\n",
       "      element.onload = on_load;\n",
       "      element.onerror = on_error;\n",
       "      element.async = false;\n",
       "      element.src = url;\n",
       "      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
       "      document.head.appendChild(element);\n",
       "    }\n",
       "    for (var i = 0; i < js_modules.length; i++) {\n",
       "      var url = js_modules[i];\n",
       "      if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n",
       "\tif (!window.requirejs) {\n",
       "\t  on_load();\n",
       "\t}\n",
       "\tcontinue;\n",
       "      }\n",
       "      var element = document.createElement('script');\n",
       "      element.onload = on_load;\n",
       "      element.onerror = on_error;\n",
       "      element.async = false;\n",
       "      element.src = url;\n",
       "      element.type = \"module\";\n",
       "      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
       "      document.head.appendChild(element);\n",
       "    }\n",
       "    for (const name in js_exports) {\n",
       "      var url = js_exports[name];\n",
       "      if (skip.indexOf(url) >= 0 || root[name] != null) {\n",
       "\tif (!window.requirejs) {\n",
       "\t  on_load();\n",
       "\t}\n",
       "\tcontinue;\n",
       "      }\n",
       "      var element = document.createElement('script');\n",
       "      element.onerror = on_error;\n",
       "      element.async = false;\n",
       "      element.type = \"module\";\n",
       "      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
       "      element.textContent = `\n",
       "      import ${name} from \"${url}\"\n",
       "      window.${name} = ${name}\n",
       "      window._bokeh_on_load()\n",
       "      `\n",
       "      document.head.appendChild(element);\n",
       "    }\n",
       "    if (!js_urls.length && !js_modules.length) {\n",
       "      on_load()\n",
       "    }\n",
       "  };\n",
       "\n",
       "  function inject_raw_css(css) {\n",
       "    const element = document.createElement(\"style\");\n",
       "    element.appendChild(document.createTextNode(css));\n",
       "    document.body.appendChild(element);\n",
       "  }\n",
       "\n",
       "  var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.2.min.js\", \"https://cdn.holoviz.org/panel/1.4.4/dist/panel.min.js\"];\n",
       "  var js_modules = [];\n",
       "  var js_exports = {};\n",
       "  var css_urls = [];\n",
       "  var inline_js = [    function(Bokeh) {\n",
       "      Bokeh.set_log_level(\"info\");\n",
       "    },\n",
       "function(Bokeh) {} // ensure no trailing comma for IE\n",
       "  ];\n",
       "\n",
       "  function run_inline_js() {\n",
       "    if ((root.Bokeh !== undefined) || (force === true)) {\n",
       "      for (var i = 0; i < inline_js.length; i++) {\n",
       "\ttry {\n",
       "          inline_js[i].call(root, root.Bokeh);\n",
       "\t} catch(e) {\n",
       "\t  if (!reloading) {\n",
       "\t    throw e;\n",
       "\t  }\n",
       "\t}\n",
       "      }\n",
       "      // Cache old bokeh versions\n",
       "      if (Bokeh != undefined && !reloading) {\n",
       "\tvar NewBokeh = root.Bokeh;\n",
       "\tif (Bokeh.versions === undefined) {\n",
       "\t  Bokeh.versions = new Map();\n",
       "\t}\n",
       "\tif (NewBokeh.version !== Bokeh.version) {\n",
       "\t  Bokeh.versions.set(NewBokeh.version, NewBokeh)\n",
       "\t}\n",
       "\troot.Bokeh = Bokeh;\n",
       "      }} else if (Date.now() < root._bokeh_timeout) {\n",
       "      setTimeout(run_inline_js, 100);\n",
       "    } else if (!root._bokeh_failed_load) {\n",
       "      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n",
       "      root._bokeh_failed_load = true;\n",
       "    }\n",
       "    root._bokeh_is_initializing = false\n",
       "  }\n",
       "\n",
       "  function load_or_wait() {\n",
       "    // Implement a backoff loop that tries to ensure we do not load multiple\n",
       "    // versions of Bokeh and its dependencies at the same time.\n",
       "    // In recent versions we use the root._bokeh_is_initializing flag\n",
       "    // to determine whether there is an ongoing attempt to initialize\n",
       "    // bokeh, however for backward compatibility we also try to ensure\n",
       "    // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n",
       "    // before older versions are fully initialized.\n",
       "    if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n",
       "      root._bokeh_is_initializing = false;\n",
       "      root._bokeh_onload_callbacks = undefined;\n",
       "      console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n",
       "      load_or_wait();\n",
       "    } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n",
       "      setTimeout(load_or_wait, 100);\n",
       "    } else {\n",
       "      root._bokeh_is_initializing = true\n",
       "      root._bokeh_onload_callbacks = []\n",
       "      var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n",
       "      if (!reloading && !bokeh_loaded) {\n",
       "\troot.Bokeh = undefined;\n",
       "      }\n",
       "      load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n",
       "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n",
       "\trun_inline_js();\n",
       "      });\n",
       "    }\n",
       "  }\n",
       "  // Give older versions of the autoload script a head-start to ensure\n",
       "  // they initialize before we start loading newer version.\n",
       "  setTimeout(load_or_wait, 100)\n",
       "}(window));"
      ],
      "application/vnd.holoviews_load.v0+json": "(function(root) {\n  function now() {\n    return new Date();\n  }\n\n  var force = true;\n  var py_version = '3.4.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n  var reloading = false;\n  var Bokeh = root.Bokeh;\n\n  if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n    root._bokeh_timeout = Date.now() + 5000;\n    root._bokeh_failed_load = false;\n  }\n\n  function run_callbacks() {\n    try {\n      root._bokeh_onload_callbacks.forEach(function(callback) {\n        if (callback != null)\n          callback();\n      });\n    } finally {\n      delete root._bokeh_onload_callbacks;\n    }\n    console.debug(\"Bokeh: all callbacks have finished\");\n  }\n\n  function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n    if (css_urls == null) css_urls = [];\n    if (js_urls == null) js_urls = [];\n    if (js_modules == null) js_modules = [];\n    if (js_exports == null) js_exports = {};\n\n    root._bokeh_onload_callbacks.push(callback);\n\n    if (root._bokeh_is_loading > 0) {\n      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n      return null;\n    }\n    if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n      run_callbacks();\n      return null;\n    }\n    if (!reloading) {\n      console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n    }\n\n    function on_load() {\n      root._bokeh_is_loading--;\n      if (root._bokeh_is_loading === 0) {\n        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n        run_callbacks()\n      }\n    }\n    window._bokeh_on_load = on_load\n\n    function on_error() {\n      console.error(\"failed to load \" + url);\n    }\n\n    var skip = [];\n    if (window.requirejs) {\n      window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n      root._bokeh_is_loading = css_urls.length + 0;\n    } else {\n      root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n    }\n\n    var existing_stylesheets = []\n    var links = document.getElementsByTagName('link')\n    for (var i = 0; i < links.length; i++) {\n      var link = links[i]\n      if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n      }\n    }\n    for (var i = 0; i < css_urls.length; i++) {\n      var url = css_urls[i];\n      if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n      }\n      const element = document.createElement(\"link\");\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.rel = \"stylesheet\";\n      element.type = \"text/css\";\n      element.href = url;\n      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n      document.body.appendChild(element);\n    }    var existing_scripts = []\n    var scripts = document.getElementsByTagName('script')\n    for (var i = 0; i < scripts.length; i++) {\n      var script = scripts[i]\n      if (script.src != null) {\n\texisting_scripts.push(script.src)\n      }\n    }\n    for (var i = 0; i < js_urls.length; i++) {\n      var url = js_urls[i];\n      if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t  on_load();\n\t}\n\tcontinue;\n      }\n      var element = document.createElement('script');\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.async = false;\n      element.src = url;\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.head.appendChild(element);\n    }\n    for (var i = 0; i < js_modules.length; i++) {\n      var url = js_modules[i];\n      if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t  on_load();\n\t}\n\tcontinue;\n      }\n      var element = document.createElement('script');\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.async = false;\n      element.src = url;\n      element.type = \"module\";\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.head.appendChild(element);\n    }\n    for (const name in js_exports) {\n      var url = js_exports[name];\n      if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t  on_load();\n\t}\n\tcontinue;\n      }\n      var element = document.createElement('script');\n      element.onerror = on_error;\n      element.async = false;\n      element.type = \"module\";\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      element.textContent = `\n      import ${name} from \"${url}\"\n      window.${name} = ${name}\n      window._bokeh_on_load()\n      `\n      document.head.appendChild(element);\n    }\n    if (!js_urls.length && !js_modules.length) {\n      on_load()\n    }\n  };\n\n  function inject_raw_css(css) {\n    const element = document.createElement(\"style\");\n    element.appendChild(document.createTextNode(css));\n    document.body.appendChild(element);\n  }\n\n  var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.2.min.js\", \"https://cdn.holoviz.org/panel/1.4.4/dist/panel.min.js\"];\n  var js_modules = [];\n  var js_exports = {};\n  var css_urls = [];\n  var inline_js = [    function(Bokeh) {\n      Bokeh.set_log_level(\"info\");\n    },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n  ];\n\n  function run_inline_js() {\n    if ((root.Bokeh !== undefined) || (force === true)) {\n      for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n          inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t  if (!reloading) {\n\t    throw e;\n\t  }\n\t}\n      }\n      // Cache old bokeh versions\n      if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t  Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t  Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n      }} else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(run_inline_js, 100);\n    } else if (!root._bokeh_failed_load) {\n      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n      root._bokeh_failed_load = true;\n    }\n    root._bokeh_is_initializing = false\n  }\n\n  function load_or_wait() {\n    // Implement a backoff loop that tries to ensure we do not load multiple\n    // versions of Bokeh and its dependencies at the same time.\n    // In recent versions we use the root._bokeh_is_initializing flag\n    // to determine whether there is an ongoing attempt to initialize\n    // bokeh, however for backward compatibility we also try to ensure\n    // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n    // before older versions are fully initialized.\n    if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n      root._bokeh_is_initializing = false;\n      root._bokeh_onload_callbacks = undefined;\n      console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n      load_or_wait();\n    } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n      setTimeout(load_or_wait, 100);\n    } else {\n      root._bokeh_is_initializing = true\n      root._bokeh_onload_callbacks = []\n      var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n      if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n      }\n      load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n      });\n    }\n  }\n  // Give older versions of the autoload script a head-start to ensure\n  // they initialize before we start loading newer version.\n  setTimeout(load_or_wait, 100)\n}(window));"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n",
       "  window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n",
       "}\n",
       "\n",
       "\n",
       "    function JupyterCommManager() {\n",
       "    }\n",
       "\n",
       "    JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n",
       "      if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
       "        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
       "        comm_manager.register_target(comm_id, function(comm) {\n",
       "          comm.on_msg(msg_handler);\n",
       "        });\n",
       "      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
       "        window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n",
       "          comm.onMsg = msg_handler;\n",
       "        });\n",
       "      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n",
       "        google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n",
       "          var messages = comm.messages[Symbol.asyncIterator]();\n",
       "          function processIteratorResult(result) {\n",
       "            var message = result.value;\n",
       "            console.log(message)\n",
       "            var content = {data: message.data, comm_id};\n",
       "            var buffers = []\n",
       "            for (var buffer of message.buffers || []) {\n",
       "              buffers.push(new DataView(buffer))\n",
       "            }\n",
       "            var metadata = message.metadata || {};\n",
       "            var msg = {content, buffers, metadata}\n",
       "            msg_handler(msg);\n",
       "            return messages.next().then(processIteratorResult);\n",
       "          }\n",
       "          return messages.next().then(processIteratorResult);\n",
       "        })\n",
       "      }\n",
       "    }\n",
       "\n",
       "    JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n",
       "      if (comm_id in window.PyViz.comms) {\n",
       "        return window.PyViz.comms[comm_id];\n",
       "      } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
       "        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
       "        var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n",
       "        if (msg_handler) {\n",
       "          comm.on_msg(msg_handler);\n",
       "        }\n",
       "      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
       "        var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n",
       "        comm.open();\n",
       "        if (msg_handler) {\n",
       "          comm.onMsg = msg_handler;\n",
       "        }\n",
       "      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n",
       "        var comm_promise = google.colab.kernel.comms.open(comm_id)\n",
       "        comm_promise.then((comm) => {\n",
       "          window.PyViz.comms[comm_id] = comm;\n",
       "          if (msg_handler) {\n",
       "            var messages = comm.messages[Symbol.asyncIterator]();\n",
       "            function processIteratorResult(result) {\n",
       "              var message = result.value;\n",
       "              var content = {data: message.data};\n",
       "              var metadata = message.metadata || {comm_id};\n",
       "              var msg = {content, metadata}\n",
       "              msg_handler(msg);\n",
       "              return messages.next().then(processIteratorResult);\n",
       "            }\n",
       "            return messages.next().then(processIteratorResult);\n",
       "          }\n",
       "        }) \n",
       "        var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n",
       "          return comm_promise.then((comm) => {\n",
       "            comm.send(data, metadata, buffers, disposeOnDone);\n",
       "          });\n",
       "        };\n",
       "        var comm = {\n",
       "          send: sendClosure\n",
       "        };\n",
       "      }\n",
       "      window.PyViz.comms[comm_id] = comm;\n",
       "      return comm;\n",
       "    }\n",
       "    window.PyViz.comm_manager = new JupyterCommManager();\n",
       "    \n",
       "\n",
       "\n",
       "var JS_MIME_TYPE = 'application/javascript';\n",
       "var HTML_MIME_TYPE = 'text/html';\n",
       "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n",
       "var CLASS_NAME = 'output';\n",
       "\n",
       "/**\n",
       " * Render data to the DOM node\n",
       " */\n",
       "function render(props, node) {\n",
       "  var div = document.createElement(\"div\");\n",
       "  var script = document.createElement(\"script\");\n",
       "  node.appendChild(div);\n",
       "  node.appendChild(script);\n",
       "}\n",
       "\n",
       "/**\n",
       " * Handle when a new output is added\n",
       " */\n",
       "function handle_add_output(event, handle) {\n",
       "  var output_area = handle.output_area;\n",
       "  var output = handle.output;\n",
       "  if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
       "    return\n",
       "  }\n",
       "  var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
       "  var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
       "  if (id !== undefined) {\n",
       "    var nchildren = toinsert.length;\n",
       "    var html_node = toinsert[nchildren-1].children[0];\n",
       "    html_node.innerHTML = output.data[HTML_MIME_TYPE];\n",
       "    var scripts = [];\n",
       "    var nodelist = html_node.querySelectorAll(\"script\");\n",
       "    for (var i in nodelist) {\n",
       "      if (nodelist.hasOwnProperty(i)) {\n",
       "        scripts.push(nodelist[i])\n",
       "      }\n",
       "    }\n",
       "\n",
       "    scripts.forEach( function (oldScript) {\n",
       "      var newScript = document.createElement(\"script\");\n",
       "      var attrs = [];\n",
       "      var nodemap = oldScript.attributes;\n",
       "      for (var j in nodemap) {\n",
       "        if (nodemap.hasOwnProperty(j)) {\n",
       "          attrs.push(nodemap[j])\n",
       "        }\n",
       "      }\n",
       "      attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n",
       "      newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n",
       "      oldScript.parentNode.replaceChild(newScript, oldScript);\n",
       "    });\n",
       "    if (JS_MIME_TYPE in output.data) {\n",
       "      toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n",
       "    }\n",
       "    output_area._hv_plot_id = id;\n",
       "    if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n",
       "      window.PyViz.plot_index[id] = Bokeh.index[id];\n",
       "    } else {\n",
       "      window.PyViz.plot_index[id] = null;\n",
       "    }\n",
       "  } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
       "    var bk_div = document.createElement(\"div\");\n",
       "    bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
       "    var script_attrs = bk_div.children[0].attributes;\n",
       "    for (var i = 0; i < script_attrs.length; i++) {\n",
       "      toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
       "    }\n",
       "    // store reference to server id on output_area\n",
       "    output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
       "  }\n",
       "}\n",
       "\n",
       "/**\n",
       " * Handle when an output is cleared or removed\n",
       " */\n",
       "function handle_clear_output(event, handle) {\n",
       "  var id = handle.cell.output_area._hv_plot_id;\n",
       "  var server_id = handle.cell.output_area._bokeh_server_id;\n",
       "  if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n",
       "  var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n",
       "  if (server_id !== null) {\n",
       "    comm.send({event_type: 'server_delete', 'id': server_id});\n",
       "    return;\n",
       "  } else if (comm !== null) {\n",
       "    comm.send({event_type: 'delete', 'id': id});\n",
       "  }\n",
       "  delete PyViz.plot_index[id];\n",
       "  if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n",
       "    var doc = window.Bokeh.index[id].model.document\n",
       "    doc.clear();\n",
       "    const i = window.Bokeh.documents.indexOf(doc);\n",
       "    if (i > -1) {\n",
       "      window.Bokeh.documents.splice(i, 1);\n",
       "    }\n",
       "  }\n",
       "}\n",
       "\n",
       "/**\n",
       " * Handle kernel restart event\n",
       " */\n",
       "function handle_kernel_cleanup(event, handle) {\n",
       "  delete PyViz.comms[\"hv-extension-comm\"];\n",
       "  window.PyViz.plot_index = {}\n",
       "}\n",
       "\n",
       "/**\n",
       " * Handle update_display_data messages\n",
       " */\n",
       "function handle_update_output(event, handle) {\n",
       "  handle_clear_output(event, {cell: {output_area: handle.output_area}})\n",
       "  handle_add_output(event, handle)\n",
       "}\n",
       "\n",
       "function register_renderer(events, OutputArea) {\n",
       "  function append_mime(data, metadata, element) {\n",
       "    // create a DOM node to render to\n",
       "    var toinsert = this.create_output_subarea(\n",
       "    metadata,\n",
       "    CLASS_NAME,\n",
       "    EXEC_MIME_TYPE\n",
       "    );\n",
       "    this.keyboard_manager.register_events(toinsert);\n",
       "    // Render to node\n",
       "    var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
       "    render(props, toinsert[0]);\n",
       "    element.append(toinsert);\n",
       "    return toinsert\n",
       "  }\n",
       "\n",
       "  events.on('output_added.OutputArea', handle_add_output);\n",
       "  events.on('output_updated.OutputArea', handle_update_output);\n",
       "  events.on('clear_output.CodeCell', handle_clear_output);\n",
       "  events.on('delete.Cell', handle_clear_output);\n",
       "  events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n",
       "\n",
       "  OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
       "    safe: true,\n",
       "    index: 0\n",
       "  });\n",
       "}\n",
       "\n",
       "if (window.Jupyter !== undefined) {\n",
       "  try {\n",
       "    var events = require('base/js/events');\n",
       "    var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
       "    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
       "      register_renderer(events, OutputArea);\n",
       "    }\n",
       "  } catch(err) {\n",
       "  }\n",
       "}\n"
      ],
      "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n  window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n    function JupyterCommManager() {\n    }\n\n    JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n      if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n        comm_manager.register_target(comm_id, function(comm) {\n          comm.on_msg(msg_handler);\n        });\n      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n        window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n          comm.onMsg = msg_handler;\n        });\n      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n        google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n          var messages = comm.messages[Symbol.asyncIterator]();\n          function processIteratorResult(result) {\n            var message = result.value;\n            console.log(message)\n            var content = {data: message.data, comm_id};\n            var buffers = []\n            for (var buffer of message.buffers || []) {\n              buffers.push(new DataView(buffer))\n            }\n            var metadata = message.metadata || {};\n            var msg = {content, buffers, metadata}\n            msg_handler(msg);\n            return messages.next().then(processIteratorResult);\n          }\n          return messages.next().then(processIteratorResult);\n        })\n      }\n    }\n\n    JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n      if (comm_id in window.PyViz.comms) {\n        return window.PyViz.comms[comm_id];\n      } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n        var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n        var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n        if (msg_handler) {\n          comm.on_msg(msg_handler);\n        }\n      } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n        var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n        comm.open();\n        if (msg_handler) {\n          comm.onMsg = msg_handler;\n        }\n      } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n        var comm_promise = google.colab.kernel.comms.open(comm_id)\n        comm_promise.then((comm) => {\n          window.PyViz.comms[comm_id] = comm;\n          if (msg_handler) {\n            var messages = comm.messages[Symbol.asyncIterator]();\n            function processIteratorResult(result) {\n              var message = result.value;\n              var content = {data: message.data};\n              var metadata = message.metadata || {comm_id};\n              var msg = {content, metadata}\n              msg_handler(msg);\n              return messages.next().then(processIteratorResult);\n            }\n            return messages.next().then(processIteratorResult);\n          }\n        }) \n        var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n          return comm_promise.then((comm) => {\n            comm.send(data, metadata, buffers, disposeOnDone);\n          });\n        };\n        var comm = {\n          send: sendClosure\n        };\n      }\n      window.PyViz.comms[comm_id] = comm;\n      return comm;\n    }\n    window.PyViz.comm_manager = new JupyterCommManager();\n    \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n  var div = document.createElement(\"div\");\n  var script = document.createElement(\"script\");\n  node.appendChild(div);\n  node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n  var output_area = handle.output_area;\n  var output = handle.output;\n  if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n    return\n  }\n  var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n  var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n  if (id !== undefined) {\n    var nchildren = toinsert.length;\n    var html_node = toinsert[nchildren-1].children[0];\n    html_node.innerHTML = output.data[HTML_MIME_TYPE];\n    var scripts = [];\n    var nodelist = html_node.querySelectorAll(\"script\");\n    for (var i in nodelist) {\n      if (nodelist.hasOwnProperty(i)) {\n        scripts.push(nodelist[i])\n      }\n    }\n\n    scripts.forEach( function (oldScript) {\n      var newScript = document.createElement(\"script\");\n      var attrs = [];\n      var nodemap = oldScript.attributes;\n      for (var j in nodemap) {\n        if (nodemap.hasOwnProperty(j)) {\n          attrs.push(nodemap[j])\n        }\n      }\n      attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n      newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n      oldScript.parentNode.replaceChild(newScript, oldScript);\n    });\n    if (JS_MIME_TYPE in output.data) {\n      toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n    }\n    output_area._hv_plot_id = id;\n    if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n      window.PyViz.plot_index[id] = Bokeh.index[id];\n    } else {\n      window.PyViz.plot_index[id] = null;\n    }\n  } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n    var bk_div = document.createElement(\"div\");\n    bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n    var script_attrs = bk_div.children[0].attributes;\n    for (var i = 0; i < script_attrs.length; i++) {\n      toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n    }\n    // store reference to server id on output_area\n    output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n  }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n  var id = handle.cell.output_area._hv_plot_id;\n  var server_id = handle.cell.output_area._bokeh_server_id;\n  if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n  var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n  if (server_id !== null) {\n    comm.send({event_type: 'server_delete', 'id': server_id});\n    return;\n  } else if (comm !== null) {\n    comm.send({event_type: 'delete', 'id': id});\n  }\n  delete PyViz.plot_index[id];\n  if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n    var doc = window.Bokeh.index[id].model.document\n    doc.clear();\n    const i = window.Bokeh.documents.indexOf(doc);\n    if (i > -1) {\n      window.Bokeh.documents.splice(i, 1);\n    }\n  }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n  delete PyViz.comms[\"hv-extension-comm\"];\n  window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n  handle_clear_output(event, {cell: {output_area: handle.output_area}})\n  handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n  function append_mime(data, metadata, element) {\n    // create a DOM node to render to\n    var toinsert = this.create_output_subarea(\n    metadata,\n    CLASS_NAME,\n    EXEC_MIME_TYPE\n    );\n    this.keyboard_manager.register_events(toinsert);\n    // Render to node\n    var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n    render(props, toinsert[0]);\n    element.append(toinsert);\n    return toinsert\n  }\n\n  events.on('output_added.OutputArea', handle_add_output);\n  events.on('output_updated.OutputArea', handle_update_output);\n  events.on('clear_output.CodeCell', handle_clear_output);\n  events.on('delete.Cell', handle_clear_output);\n  events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n  OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n    safe: true,\n    index: 0\n  });\n}\n\nif (window.Jupyter !== undefined) {\n  try {\n    var events = require('base/js/events');\n    var OutputArea = require('notebook/js/outputarea').OutputArea;\n    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n      register_renderer(events, OutputArea);\n    }\n  } catch(err) {\n  }\n}\n"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<style>*[data-root-id],\n",
       "*[data-root-id] > * {\n",
       "  box-sizing: border-box;\n",
       "  font-family: var(--jp-ui-font-family);\n",
       "  font-size: var(--jp-ui-font-size1);\n",
       "  color: var(--vscode-editor-foreground, var(--jp-ui-font-color1));\n",
       "}\n",
       "\n",
       "/* Override VSCode background color */\n",
       ".cell-output-ipywidget-background:has(\n",
       "    > .cell-output-ipywidget-background > .lm-Widget > *[data-root-id]\n",
       "  ),\n",
       ".cell-output-ipywidget-background:has(> .lm-Widget > *[data-root-id]) {\n",
       "  background-color: transparent !important;\n",
       "}\n",
       "</style>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.holoviews_exec.v0+json": "",
      "text/html": [
       "<div id='p1002'>\n",
       "  <div id=\"b1ed2aec-90af-40ac-8d59-4adcf7c466df\" data-root-id=\"p1002\" style=\"display: contents;\"></div>\n",
       "</div>\n",
       "<script type=\"application/javascript\">(function(root) {\n",
       "  var docs_json = {\"d49919a4-f3bd-4c35-8118-6bf45d760fdd\":{\"version\":\"3.4.2\",\"title\":\"Bokeh Application\",\"roots\":[{\"type\":\"object\",\"name\":\"panel.models.browser.BrowserInfo\",\"id\":\"p1002\"},{\"type\":\"object\",\"name\":\"panel.models.comm_manager.CommManager\",\"id\":\"p1003\",\"attributes\":{\"plot_id\":\"p1002\",\"comm_id\":\"cb2e0f9daa954348abb19b42f2c86f87\",\"client_comm_id\":\"6f7df9607aa145c6bbfc7f4601cee504\"}}],\"defs\":[{\"type\":\"model\",\"name\":\"ReactiveHTML1\"},{\"type\":\"model\",\"name\":\"FlexBox1\",\"properties\":[{\"name\":\"align_content\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"align_items\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"flex_direction\",\"kind\":\"Any\",\"default\":\"row\"},{\"name\":\"flex_wrap\",\"kind\":\"Any\",\"default\":\"wrap\"},{\"name\":\"gap\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"justify_content\",\"kind\":\"Any\",\"default\":\"flex-start\"}]},{\"type\":\"model\",\"name\":\"FloatPanel1\",\"properties\":[{\"name\":\"config\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"contained\",\"kind\":\"Any\",\"default\":true},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"right-top\"},{\"name\":\"offsetx\",\"kind\":\"Any\",\"default\":null},{\"name\":\"offsety\",\"kind\":\"Any\",\"default\":null},{\"name\":\"theme\",\"kind\":\"Any\",\"default\":\"primary\"},{\"name\":\"status\",\"kind\":\"Any\",\"default\":\"normalized\"}]},{\"type\":\"model\",\"name\":\"GridStack1\",\"properties\":[{\"name\":\"mode\",\"kind\":\"Any\",\"default\":\"warn\"},{\"name\":\"ncols\",\"kind\":\"Any\",\"default\":null},{\"name\":\"nrows\",\"kind\":\"Any\",\"default\":null},{\"name\":\"allow_resize\",\"kind\":\"Any\",\"default\":true},{\"name\":\"allow_drag\",\"kind\":\"Any\",\"default\":true},{\"name\":\"state\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"drag1\",\"properties\":[{\"name\":\"slider_width\",\"kind\":\"Any\",\"default\":5},{\"name\":\"slider_color\",\"kind\":\"Any\",\"default\":\"black\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":50}]},{\"type\":\"model\",\"name\":\"click1\",\"properties\":[{\"name\":\"terminal_output\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"debug_name\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"clears\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"FastWrapper1\",\"properties\":[{\"name\":\"object\",\"kind\":\"Any\",\"default\":null},{\"name\":\"style\",\"kind\":\"Any\",\"default\":null}]},{\"type\":\"model\",\"name\":\"NotificationAreaBase1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"NotificationArea1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"notifications\",\"kind\":\"Any\",\"default\":[]},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0},{\"name\":\"types\",\"kind\":\"Any\",\"default\":[{\"type\":\"map\",\"entries\":[[\"type\",\"warning\"],[\"background\",\"#ffc107\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-exclamation-triangle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]},{\"type\":\"map\",\"entries\":[[\"type\",\"info\"],[\"background\",\"#007bff\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-info-circle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]}]}]},{\"type\":\"model\",\"name\":\"Notification\",\"properties\":[{\"name\":\"background\",\"kind\":\"Any\",\"default\":null},{\"name\":\"duration\",\"kind\":\"Any\",\"default\":3000},{\"name\":\"icon\",\"kind\":\"Any\",\"default\":null},{\"name\":\"message\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"notification_type\",\"kind\":\"Any\",\"default\":null},{\"name\":\"_destroyed\",\"kind\":\"Any\",\"default\":false}]},{\"type\":\"model\",\"name\":\"TemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"BootstrapTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"TemplateEditor1\",\"properties\":[{\"name\":\"layout\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"MaterialTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"copy_to_clipboard1\",\"properties\":[{\"name\":\"fill\",\"kind\":\"Any\",\"default\":\"none\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":null}]}]}};\n",
       "  var render_items = [{\"docid\":\"d49919a4-f3bd-4c35-8118-6bf45d760fdd\",\"roots\":{\"p1002\":\"b1ed2aec-90af-40ac-8d59-4adcf7c466df\"},\"root_ids\":[\"p1002\"]}];\n",
       "  var docs = Object.values(docs_json)\n",
       "  if (!docs) {\n",
       "    return\n",
       "  }\n",
       "  const py_version = docs[0].version.replace('rc', '-rc.').replace('.dev', '-dev.')\n",
       "  async function embed_document(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    await Bokeh.embed.embed_items_notebook(docs_json, render_items);\n",
       "    for (const render_item of render_items) {\n",
       "      for (const root_id of render_item.root_ids) {\n",
       "\tconst id_el = document.getElementById(root_id)\n",
       "\tif (id_el.children.length && id_el.children[0].hasAttribute('data-root-id')) {\n",
       "\t  const root_el = id_el.children[0]\n",
       "\t  root_el.id = root_el.id + '-rendered'\n",
       "\t  for (const child of root_el.children) {\n",
       "            // Ensure JupyterLab does not capture keyboard shortcuts\n",
       "            // see: https://jupyterlab.readthedocs.io/en/4.1.x/extension/notebook.html#keyboard-interaction-model\n",
       "\t    child.setAttribute('data-lm-suppress-shortcuts', 'true')\n",
       "\t  }\n",
       "\t}\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "  function get_bokeh(root) {\n",
       "    if (root.Bokeh === undefined) {\n",
       "      return null\n",
       "    } else if (root.Bokeh.version !== py_version) {\n",
       "      if (root.Bokeh.versions === undefined || !root.Bokeh.versions.has(py_version)) {\n",
       "\treturn null\n",
       "      }\n",
       "      return root.Bokeh.versions.get(py_version);\n",
       "    } else if (root.Bokeh.version === py_version) {\n",
       "      return root.Bokeh\n",
       "    }\n",
       "    return null\n",
       "  }\n",
       "  function is_loaded(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    return (Bokeh != null && Bokeh.Panel !== undefined)\n",
       "  }\n",
       "  if (is_loaded(root)) {\n",
       "    embed_document(root);\n",
       "  } else {\n",
       "    var attempts = 0;\n",
       "    var timer = setInterval(function(root) {\n",
       "      if (is_loaded(root)) {\n",
       "        clearInterval(timer);\n",
       "        embed_document(root);\n",
       "      } else if (document.readyState == \"complete\") {\n",
       "        attempts++;\n",
       "        if (attempts > 200) {\n",
       "          clearInterval(timer);\n",
       "\t  var Bokeh = get_bokeh(root)\n",
       "\t  if (Bokeh == null || Bokeh.Panel == null) {\n",
       "            console.warn(\"Panel: ERROR: Unable to run Panel code because Bokeh or Panel library is missing\");\n",
       "\t  } else {\n",
       "\t    console.warn(\"Panel: WARNING: Attempting to render but not all required libraries could be resolved.\")\n",
       "\t    embed_document(root)\n",
       "\t  }\n",
       "        }\n",
       "      }\n",
       "    }, 25, root)\n",
       "  }\n",
       "})(window);</script>"
      ]
     },
     "metadata": {
      "application/vnd.holoviews_exec.v0+json": {
       "id": "p1002"
      }
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<div class=\"logo-block\">\n",
       "<img src='\n",
       "AAAB+wAAAfsBxc2miwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAA6zSURB\n",
       "VHic7ZtpeFRVmsf/5966taWqUlUJ2UioBBJiIBAwCZtog9IOgjqACsogKtqirT2ttt069nQ/zDzt\n",
       "tI4+CrJIREFaFgWhBXpUNhHZQoKBkIUASchWla1S+3ar7r1nPkDaCAnZKoQP/D7mnPOe9/xy76n3\n",
       "nFSAW9ziFoPFNED2LLK5wcyBDObkb8ZkxuaoSYlI6ZcOKq1eWFdedqNzGHQBk9RMEwFAASkk0Xw3\n",
       "ETacDNi2vtvc7L0ROdw0AjoSotQVkKSvHQz/wRO1lScGModBFbDMaNRN1A4tUBCS3lk7BWhQkgpD\n",
       "lG4852/+7DWr1R3uHAZVQDsbh6ZPN7CyxUrCzJMRouusj0ipRwD2uKm0Zn5d2dFwzX1TCGhnmdGo\n",
       "G62Nna+isiUqhkzuKrkQaJlPEv5mFl2fvGg2t/VnzkEV8F5ioioOEWkLG86fvbpthynjdhXYZziQ\n",
       "x1hC9J2NFyi8vCTt91Fh04KGip0AaG9zuCk2wQCVyoNU3Hjezee9bq92duzzTmxsRJoy+jEZZZYo\n",
       "GTKJ6SJngdJqAfRzpze0+jHreUtPc7gpBLQnIYK6BYp/uGhw9YK688eu7v95ysgshcg9qSLMo3JC\n",
       "4jqLKQFBgdKDPoQ+Pltb8dUyQLpeDjeVgI6EgLIQFT5tEl3rn2losHVsexbZ3EyT9wE1uGdkIPcy\n",
       "BGxn8QUq1QrA5nqW5i2tLqvrrM9NK6AdkVIvL9E9bZL/oyfMVd/jqvc8LylzRBKDJSzIExwhQzuL\n",
       "QYGQj4rHfFTc8mUdu3E7yoLtbTe9gI4EqVgVkug2i5+uXGo919ixbRog+3fTbQ8qJe4ZOYNfMoTI\n",
       "OoshUNosgO60AisX15aeI2PSIp5KiFLI9ubb1vV3Qb2ltwLakUCDAkWX7/nHKRmmGIl9VgYsUhJm\n",
       "2NXjKYADtM1ygne9QQDIXlk49FBstMKx66D1v4+XuQr7vqTe0VcBHQlRWiOCbmmSYe2SqtL6q5rJ\n",
       "zsTb7lKx3FKOYC4DoqyS/B5bvLPxvD9Qtf6saxYLQGJErmDOdOMr/zo96km1nElr8bmPOBwI9COv\n",
       "HnFPRIwmkSOv9kcAS4heRsidOkpeWBgZM+UBrTFAXNYL5Vf2ii9c1trNzpYdaoVil3WIc+wdk+gQ\n",
       "noie3ecCcxt9ITcLAPWt/laGEO/9U6PmzZkenTtsSMQ8uYywJVW+grCstAvCIaAdArAsIWkRDDs/\n",
       "KzLm2YcjY1Lv0UdW73HabE9n6V66cxSzfEmuJssTpKGVp+0vHq73FwL46eOjpMpbRAnNmJFrGJNu\n",
       "Ukf9Yrz+3rghiumCKNXXWPhLYcjxGsIpoCMsIRoFITkW8AuyM8jC1+/QLx4bozCEJIq38+1rtpR6\n",
       "V/yzb8eBlRb3fo5l783N0CWolAzJHaVNzkrTzlEp2bQ2q3TC5gn6wpnoQAmwSiGh2GitnTmVMc5O\n",
       "UyfKWUKCIsU7+fZDKwqdT6DDpvkzAX4/+AMFjk0tDp5GRXLpQ2MUmhgDp5gxQT8+Y7hyPsMi8uxF\n",
       "71H0oebujHALECjFKaW9Lm68n18wXp2kVzIcABytD5iXFzg+WVXkegpAsOOYziqo0OkK76GyquC3\n",
       "ltZAzMhhqlSNmmWTE5T6e3IN05ITFLM4GdN0vtZ3ob8Jh1NAKXFbm5PtLU/eqTSlGjkNAJjdgn/N\n",
       "aedXa0tdi7+t9G0FIF49rtMSEgAs1kDLkTPO7ebm4IUWeyh1bKomXqlgMG6kJmHcSM0clYLJ8XtR\n",
       "1GTnbV3F6I5wCGikAb402npp1h1s7LQUZZSMIfALFOuL3UUrfnS8+rez7v9qcold5tilgHbO1fjK\n",
       "9ubb17u9oshxzMiUBKXWqJNxd+fqb0tLVs4lILFnK71H0Ind7uiPgACVcFJlrb0tV6DzxqqTIhUM\n",
       "CwDf1/rrVhTa33/3pGPxJYdQ2l2cbgVcQSosdx8uqnDtbGjh9SlDVSMNWhlnilfqZk42Th2ZpLpf\n",
       "xrHec5e815zrr0dfBZSwzkZfqsv+1FS1KUknUwPARVvItfKUY+cn57yP7qv07UE3p8B2uhUwLk09\n",
       "e0SCOrK+hbdYHYLjRIl71wWzv9jpEoeOHhGRrJAzyEyNiJuUqX0g2sBN5kGK6y2Blp5M3lsB9Qh4\n",
       "y2Ja6x6+i0ucmKgwMATwhSjdUu49tKrQ/pvN5d53ml2CGwCmJipmKjgmyuaXzNeL2a0AkQ01Th5j\n",
       "2DktO3Jyk8f9vcOBQHV94OK+fPumJmvQHxJoWkaKWq9Vs+yUsbq0zGT1I4RgeH2b5wef7+c7bl8F\n",
       "eKgoHVVZa8ZPEORzR6sT1BzDUAD/d9F78e2Tzv99v8D+fLVTqAKAsbGamKey1Mt9Ann4eH3gTXTz\n",
       "idWtAJ8PQWOk7NzSeQn/OTHDuEikVF1R4z8BQCy+6D1aWRfY0tTGG2OM8rRoPaeIj5ZHzJxszElN\n",
       "VM8K8JS5WOfv8mzRnQAKoEhmt8gyPM4lU9SmBK1MCQBnW4KONT86v1hZ1PbwSXPw4JWussVjtH9Y\n",
       "NCoiL9UoH/6PSu8jFrfY2t36erQHXLIEakMi1SydmzB31h3GGXFDFNPaK8Rme9B79Ixrd0WN+1ij\n",
       "NRQ/doRmuFLBkHSTOm5GruG+pFjFdAmorG4IXH1Qua6ASniclfFtDYt+oUjKipPrCQB7QBQ2lrgP\n",
       "fFzm+9XWUtcqJ3/5vDLDpJ79XHZk3u8nGZ42qlj1+ydtbxysCezrydp6ugmipNJ7WBPB5tydY0jP\n",
       "HaVNzs3QzeE4ZpTbI+ZbnSFPbVOw9vsfnVvqWnirPyCNGD08IlqtYkh2hjZ5dErEQzoNm+6ykyOt\n",
       "Lt5/PQEuSRRKo22VkydK+vvS1XEKlhCJAnsqvcVvH7f/ZU2R67eXbMEGAMiIV5oWZWiWvz5Fv2xG\n",
       "sjqNJQRvn3Rs2lji/lNP19VjAQDgD7FHhujZB9OGqYxRkZxixgRDVlqS6uEOFaJUVu0rPFzctrnF\n",
       "JqijImVp8dEKVWyUXDk92zAuMZ6bFwpBU1HrOw6AdhQgUooChb0+ItMbWJitSo5Ws3IAOGEOtL53\n",
       "0vHZih9sC4vtofZ7Qu6523V/fmGcds1TY3V36pUsBwAbSlxnVh2xLfAD/IAIMDf7XYIkNmXfpp2l\n",
       "18rkAJAy9HKFaIr/qULkeQQKy9zf1JgDB2uaeFNGijo5QsUyacNUUTOnGO42xSnv4oOwpDi1zYkc\n",
       "efUc3I5Gk6PhyTuVKaOGyLUAYPGIoY9Pu/atL/L92+4q9wbflRJ2Trpm/jPjdBtfnqB/dIThcl8A\n",
       "KG7hbRuKnb8qsQsVvVlTrwQAQMUlf3kwJI24Z4JhPMtcfng5GcH49GsrxJpGvvHIaeem2ma+KSjQ\n",
       "lIwUdYyCY8j4dE1KzijNnIP2llF2wcXNnsoapw9XxsgYAl6k+KzUXbi2yP3KR2ecf6z3BFsBICdW\n",
       "nvnIaG3eHybqX7vbpEqUMT+9OL4Qpe8VON7dXuFd39v19FoAABRVePbGGuXTszO0P7tu6lghUonE\n",
       "llRdrhArLvmKdh9u29jcFiRRkfLUxBiFNiqSU9icoZQHo5mYBI1MBgBH6wMNb+U7Pnw337H4gi1Y\n",
       "ciWs+uks3Z9fztUvfzxTm9Ne8XXkvQLHNytOOZeiD4e0PgkAIAYCYknKUNUDSXEKzdWNpnil7r4p\n",
       "xqkjTarZMtk/K8TQ6Qve78qqvXurGwIJqcOUKfUWHsm8KGvxSP68YudXq4pcj39X49uOK2X142O0\n",
       "Tz5/u/7TVybqH0rSya6ZBwD21/gubbrgWdDgEOx9WUhfBaC2ibcEBYm7a7x+ukrBMNcEZggyR0TE\n",
       "T8zUPjikQ4VosQZbTpS4vqizBKvqmvjsqnpfzaZyx9JPiz1/bfGKdgD45XB1zoIMzYbfTdS/NClB\n",
       "Gct0USiY3YL/g0LHy/uq/Ef6uo5+n0R/vyhp17Klpge763f8rMu6YU/zrn2nml+2WtH+Z+5IAAFc\n",
       "2bUTdTDOSNa9+cQY7YLsOIXhevEkCvzph7a8laecz/Un/z4/Ae04XeL3UQb57IwU9ZDr9UuKVajv\n",
       "nxp1+1UVIo/LjztZkKH59fO3G/JemqCfmaCRqbqbd90ZZ8FfjtkfAyD0J/9+C2h1hDwsSxvGjNDc\n",
       "b4zk5NfrSwiQblLHzZhg+Jf4aPlUwpDqkQqa9nimbt1/TDH8OitGMaQnj+RJS6B1fbF7SY1TqO5v\n",
       "/v0WAADl1f7zokgS7s7VT2DZ7pegUjBM7mjtiDZbcN4j0YrHH0rXpCtY0qPX0cVL0rv5jv/ZXend\n",
       "0u/EESYBAFBU4T4Qa5TflZOhTe7pmKpaP8kCVUVw1+yhXfJWvn1P3hnXi33JsTN6PnP3hHZ8Z3/h\n",
       "aLHzmkNPuPj7Bc/F/Q38CwjTpSwQXgE4Vmwry9tpfq/ZFgqFMy4AVDtCvi8rvMvOmv0N4YwbVgEA\n",
       "sPM72/KVnzfspmH7HQGCRLG2yL1+z8XwvPcdCbsAANh+xPzstgMtxeGKt+6MK3/tacfvwhWvIwMi\n",
       "oKEBtm0H7W+UVfkc/Y1V0BhoPlDr/w1w/eu1vjIgAgDg22OtX6/eYfnEz/focrZTHAFR+PSs56/7\n",
       "q32nwpjazxgwAQCwcU/T62t3WL7r6/jVRa6/byp1rei+Z98ZUAEAhEPHPc8fKnTU9nbgtnOe8h0l\n",
       "9hcGIqmODLQAHCy2Xti6v/XNRivf43f4fFvIteu854+VHnR7q9tfBlwAAGz+pnndB9vM26UebAe8\n",
       "SLHujPOTPVW+rwY+sxskAAC2HrA8t2Vvc7ffP1r9o+vwR2dcr92InIAbKKC1FZ5tB1tf+/G8p8sv\n",
       "N/9Q5zd/XR34LYCwV5JdccMEAMDBk45DH243r/X4xGvqxFa/GNpS7n6rwOwNWwHVE26oAADYurf1\n",
       "zx/utOzt+DMKYM0p17YtZZ5VNzqfsB2HewG1WXE8PoZ7gOclbTIvynZf9JV+fqZtfgs/8F/Nu5rB\n",
       "EIBmJ+8QRMmpU7EzGRsf2FzuePqYRbzh/zE26EwdrT10f6r6o8HOYzCJB9Dpff8tbnGLG8L/A/WE\n",
       "roTBs2RqAAAAAElFTkSuQmCC'\n",
       "     style='height:25px; border-radius:12px; display: inline-block; float: left; vertical-align: middle'></img>\n",
       "\n",
       "\n",
       "  <img src=''\n",
       "       style='height:15px; border-radius:12px; display: inline-block; float: left'></img>\n",
       "  \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "</div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {},
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.holoviews_exec.v0+json": "",
      "text/html": [
       "<div id='p1004'>\n",
       "  <div id=\"b3290d1f-435b-461c-9bf5-907742f846a0\" data-root-id=\"p1004\" style=\"display: contents;\"></div>\n",
       "</div>\n",
       "<script type=\"application/javascript\">(function(root) {\n",
       "  var docs_json = {\"a3878d75-7d3e-46d1-a5b5-1cc5cbbb9131\":{\"version\":\"3.4.2\",\"title\":\"Bokeh Application\",\"roots\":[{\"type\":\"object\",\"name\":\"Row\",\"id\":\"p1004\",\"attributes\":{\"name\":\"Row01003\",\"tags\":[\"embedded\"],\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1007\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/css/loading.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1111\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/css/listpanel.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1005\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/bundled/theme/default.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1006\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/bundled/theme/native.css\"}}],\"min_width\":700,\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\",\"children\":[{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1008\",\"attributes\":{\"name\":\"HSpacer01010\",\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1007\"},{\"id\":\"p1005\"},{\"id\":\"p1006\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}},{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1022\",\"attributes\":{\"width\":700,\"height\":300,\"margin\":[5,10],\"sizing_mode\":\"fixed\",\"align\":\"start\",\"x_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1009\",\"attributes\":{\"tags\":[[[\"Local Timestamp\",null]],[]],\"start\":1723161611500.0,\"end\":1723161901500.0,\"reset_start\":1723161611500.0,\"reset_end\":1723161901500.0}},\"y_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1010\",\"attributes\":{\"tags\":[[[\"value\",null]],{\"type\":\"map\",\"entries\":[[\"invert_yaxis\",false],[\"autorange\",false]]}],\"start\":-4300.170700000007,\"end\":397.04570000000064,\"reset_start\":-4300.170700000007,\"reset_end\":397.04570000000064}},\"x_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1032\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1033\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1025\",\"attributes\":{\"text_color\":\"black\",\"text_font_size\":\"12pt\"}},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1074\",\"attributes\":{\"name\":\"TOB Imbalance\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1065\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1066\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1067\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"okW28/3UBUDLoUW2830SQFyPwvUo3BnA5KWbxCCwH8CsHFpkO98DwBKDwMqhRfw/vp8aL90kBcCJQWDl0CIMwHE9CtejcM2/76fGSzeJ9T9zaJHtfD8GQADFILByaJG/bLx0kxgE4j+0yHa+nxrrv2ZmZmZm5hvAgZVDi2zn9T/gT42XbhL1v4ts5/upcRZAaGZmZmZm5r8aBFYOLbL/PwgCK4cW2d4/DAIrhxbZBkCAarx0kxjcv30/NV66SQpAj8L1KFyPA0A5tMh2vp8OQJmZmZmZmfW/1HjpJjEIDsA0MzMzMzMEwI/C9Shcj/4/\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\",\"TOB Imbalance\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1075\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1076\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1071\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1079\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1072\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1073\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1089\",\"attributes\":{\"name\":\"0.5% Imbalance\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1080\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1081\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1082\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"bEOLbGdQm8Dm1qNwvVWbwO4BK4eWr5PA/NajcL1YksDDzvdTY+6RwPerHFrkK5DAd2q8dJPwgMAltMh2vvWAwFg7308NgZHArMzMzMyPgcDmgJVDi/+AwCWLbOf7zYDASg4tsp1rkMDDeOkmMaGRwBLb+X5qh5LAhMQgsHLukcCnHoXr0YuSwPHWo3A9n5DApsh2vp/9kcBNj8L1qMaRwJ90kxgELIHA7lUOLTKCkcAmXrpJDHeRwEw730+NKJHA0E+Nl+6KkcBd5/up8YiSwKh0kxiE0ZTA1iQGgRU6ksAA16NwPZKSwJZyaJHtl4LA\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\",\"0.5% Imbalance\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1090\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1091\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1086\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1093\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1087\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1088\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1103\",\"attributes\":{\"name\":\"1% Imbalance\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1094\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1095\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1096\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"xPP91HiJrsBQCtejsHGrwAopXI+CO6rAco/C9egfq8BCXI/C9QqrwAv+1HgpC6XAN9v5fuq7oMC58dJNYiehwNKfGi8dgKbAom4Sg8DpoMAfrkfh+uSgwDzdJAYB6qDAvsZLN0lnpcAuVg4tsn+rwJYSg8BKBqvAomq8dJOaqsBU3SQGwfiqwLbtfD81GarAIH9qvLQnpcBTXI/C9R+lwGQGgZXDyZ/AMAAAAMBlpcBOsHJoURylwFcGgZWD+qTATdnO99N3qsD29Shcj7+rwNPtfD+1e6vADk5iEFgLpcBA2c730zmlwJw9CtejtaDA\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\",\"1% Imbalance\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1104\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1105\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1100\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1107\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1101\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1102\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_alpha\":0.2,\"line_width\":2}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1031\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1014\",\"attributes\":{\"tags\":[\"hv_created\"],\"renderers\":\"auto\",\"zoom_together\":\"none\"}},{\"type\":\"object\",\"name\":\"HoverTool\",\"id\":\"p1015\",\"attributes\":{\"tags\":[\"hv_created\"],\"renderers\":[{\"id\":\"p1074\"},{\"id\":\"p1089\"},{\"id\":\"p1103\"}],\"tooltips\":[[\"Variable\",\"@{Variable}\"],[\"Local Timestamp\",\"@{Local_Timestamp}{%F %T}\"],[\"value\",\"@{value}\"]],\"formatters\":{\"type\":\"map\",\"entries\":[[\"@{Local Timestamp}\",\"datetime\"],[\"@{Local_Timestamp}\",\"datetime\"]]}}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1056\"},{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1057\"},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1058\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1059\",\"attributes\":{\"syncable\":false,\"level\":\"overlay\",\"visible\":false,\"left\":{\"type\":\"number\",\"value\":\"nan\"},\"right\":{\"type\":\"number\",\"value\":\"nan\"},\"top\":{\"type\":\"number\",\"value\":\"nan\"},\"bottom\":{\"type\":\"number\",\"value\":\"nan\"},\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"top_units\":\"canvas\",\"bottom_units\":\"canvas\",\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5}}}},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1064\"}],\"active_drag\":{\"id\":\"p1057\"},\"active_scroll\":{\"id\":\"p1014\"}}},\"left\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1051\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1052\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1053\"},\"axis_label\":\"\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1054\"}}}],\"right\":[{\"type\":\"object\",\"name\":\"Legend\",\"id\":\"p1077\",\"attributes\":{\"location\":[0,0],\"title\":\"Variable\",\"click_policy\":\"mute\",\"items\":[{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1078\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"TOB Imbalance\"},\"renderers\":[{\"id\":\"p1074\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1092\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"0.5% Imbalance\"},\"renderers\":[{\"id\":\"p1089\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1106\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"1% Imbalance\"},\"renderers\":[{\"id\":\"p1103\"}]}}]}}],\"below\":[{\"type\":\"object\",\"name\":\"DatetimeAxis\",\"id\":\"p1034\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"DatetimeTicker\",\"id\":\"p1035\",\"attributes\":{\"num_minor_ticks\":5,\"tickers\":[{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1036\",\"attributes\":{\"num_minor_ticks\":0,\"mantissas\":[1,2,5],\"max_interval\":500.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1037\",\"attributes\":{\"num_minor_ticks\":0,\"base\":60,\"mantissas\":[1,2,5,10,15,20,30],\"min_interval\":1000.0,\"max_interval\":1800000.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1038\",\"attributes\":{\"num_minor_ticks\":0,\"base\":24,\"mantissas\":[1,2,4,6,8,12],\"min_interval\":3600000.0,\"max_interval\":43200000.0}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1039\",\"attributes\":{\"days\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1040\",\"attributes\":{\"days\":[1,4,7,10,13,16,19,22,25,28]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1041\",\"attributes\":{\"days\":[1,8,15,22]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1042\",\"attributes\":{\"days\":[1,15]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1043\",\"attributes\":{\"months\":[0,1,2,3,4,5,6,7,8,9,10,11]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1044\",\"attributes\":{\"months\":[0,2,4,6,8,10]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1045\",\"attributes\":{\"months\":[0,4,8]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1046\",\"attributes\":{\"months\":[0,6]}},{\"type\":\"object\",\"name\":\"YearsTicker\",\"id\":\"p1047\"}]}},\"formatter\":{\"type\":\"object\",\"name\":\"DatetimeTickFormatter\",\"id\":\"p1048\"},\"axis_label\":\"Local Timestamp\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1049\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1050\",\"attributes\":{\"axis\":{\"id\":\"p1034\"},\"grid_line_color\":null}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1055\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1051\"},\"grid_line_color\":null}}],\"min_border_top\":10,\"min_border_bottom\":10,\"min_border_left\":10,\"min_border_right\":10,\"output_backend\":\"webgl\"}},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1109\",\"attributes\":{\"name\":\"HSpacer01011\",\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1007\"},{\"id\":\"p1005\"},{\"id\":\"p1006\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}}]}}],\"defs\":[{\"type\":\"model\",\"name\":\"ReactiveHTML1\"},{\"type\":\"model\",\"name\":\"FlexBox1\",\"properties\":[{\"name\":\"align_content\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"align_items\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"flex_direction\",\"kind\":\"Any\",\"default\":\"row\"},{\"name\":\"flex_wrap\",\"kind\":\"Any\",\"default\":\"wrap\"},{\"name\":\"gap\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"justify_content\",\"kind\":\"Any\",\"default\":\"flex-start\"}]},{\"type\":\"model\",\"name\":\"FloatPanel1\",\"properties\":[{\"name\":\"config\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"contained\",\"kind\":\"Any\",\"default\":true},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"right-top\"},{\"name\":\"offsetx\",\"kind\":\"Any\",\"default\":null},{\"name\":\"offsety\",\"kind\":\"Any\",\"default\":null},{\"name\":\"theme\",\"kind\":\"Any\",\"default\":\"primary\"},{\"name\":\"status\",\"kind\":\"Any\",\"default\":\"normalized\"}]},{\"type\":\"model\",\"name\":\"GridStack1\",\"properties\":[{\"name\":\"mode\",\"kind\":\"Any\",\"default\":\"warn\"},{\"name\":\"ncols\",\"kind\":\"Any\",\"default\":null},{\"name\":\"nrows\",\"kind\":\"Any\",\"default\":null},{\"name\":\"allow_resize\",\"kind\":\"Any\",\"default\":true},{\"name\":\"allow_drag\",\"kind\":\"Any\",\"default\":true},{\"name\":\"state\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"drag1\",\"properties\":[{\"name\":\"slider_width\",\"kind\":\"Any\",\"default\":5},{\"name\":\"slider_color\",\"kind\":\"Any\",\"default\":\"black\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":50}]},{\"type\":\"model\",\"name\":\"click1\",\"properties\":[{\"name\":\"terminal_output\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"debug_name\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"clears\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"FastWrapper1\",\"properties\":[{\"name\":\"object\",\"kind\":\"Any\",\"default\":null},{\"name\":\"style\",\"kind\":\"Any\",\"default\":null}]},{\"type\":\"model\",\"name\":\"NotificationAreaBase1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"NotificationArea1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"notifications\",\"kind\":\"Any\",\"default\":[]},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0},{\"name\":\"types\",\"kind\":\"Any\",\"default\":[{\"type\":\"map\",\"entries\":[[\"type\",\"warning\"],[\"background\",\"#ffc107\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-exclamation-triangle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]},{\"type\":\"map\",\"entries\":[[\"type\",\"info\"],[\"background\",\"#007bff\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-info-circle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]}]}]},{\"type\":\"model\",\"name\":\"Notification\",\"properties\":[{\"name\":\"background\",\"kind\":\"Any\",\"default\":null},{\"name\":\"duration\",\"kind\":\"Any\",\"default\":3000},{\"name\":\"icon\",\"kind\":\"Any\",\"default\":null},{\"name\":\"message\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"notification_type\",\"kind\":\"Any\",\"default\":null},{\"name\":\"_destroyed\",\"kind\":\"Any\",\"default\":false}]},{\"type\":\"model\",\"name\":\"TemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"BootstrapTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"TemplateEditor1\",\"properties\":[{\"name\":\"layout\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"MaterialTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"copy_to_clipboard1\",\"properties\":[{\"name\":\"fill\",\"kind\":\"Any\",\"default\":\"none\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":null}]}]}};\n",
       "  var render_items = [{\"docid\":\"a3878d75-7d3e-46d1-a5b5-1cc5cbbb9131\",\"roots\":{\"p1004\":\"b3290d1f-435b-461c-9bf5-907742f846a0\"},\"root_ids\":[\"p1004\"]}];\n",
       "  var docs = Object.values(docs_json)\n",
       "  if (!docs) {\n",
       "    return\n",
       "  }\n",
       "  const py_version = docs[0].version.replace('rc', '-rc.').replace('.dev', '-dev.')\n",
       "  async function embed_document(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    await Bokeh.embed.embed_items_notebook(docs_json, render_items);\n",
       "    for (const render_item of render_items) {\n",
       "      for (const root_id of render_item.root_ids) {\n",
       "\tconst id_el = document.getElementById(root_id)\n",
       "\tif (id_el.children.length && id_el.children[0].hasAttribute('data-root-id')) {\n",
       "\t  const root_el = id_el.children[0]\n",
       "\t  root_el.id = root_el.id + '-rendered'\n",
       "\t  for (const child of root_el.children) {\n",
       "            // Ensure JupyterLab does not capture keyboard shortcuts\n",
       "            // see: https://jupyterlab.readthedocs.io/en/4.1.x/extension/notebook.html#keyboard-interaction-model\n",
       "\t    child.setAttribute('data-lm-suppress-shortcuts', 'true')\n",
       "\t  }\n",
       "\t}\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "  function get_bokeh(root) {\n",
       "    if (root.Bokeh === undefined) {\n",
       "      return null\n",
       "    } else if (root.Bokeh.version !== py_version) {\n",
       "      if (root.Bokeh.versions === undefined || !root.Bokeh.versions.has(py_version)) {\n",
       "\treturn null\n",
       "      }\n",
       "      return root.Bokeh.versions.get(py_version);\n",
       "    } else if (root.Bokeh.version === py_version) {\n",
       "      return root.Bokeh\n",
       "    }\n",
       "    return null\n",
       "  }\n",
       "  function is_loaded(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    return (Bokeh != null && Bokeh.Panel !== undefined)\n",
       "  }\n",
       "  if (is_loaded(root)) {\n",
       "    embed_document(root);\n",
       "  } else {\n",
       "    var attempts = 0;\n",
       "    var timer = setInterval(function(root) {\n",
       "      if (is_loaded(root)) {\n",
       "        clearInterval(timer);\n",
       "        embed_document(root);\n",
       "      } else if (document.readyState == \"complete\") {\n",
       "        attempts++;\n",
       "        if (attempts > 200) {\n",
       "          clearInterval(timer);\n",
       "\t  var Bokeh = get_bokeh(root)\n",
       "\t  if (Bokeh == null || Bokeh.Panel == null) {\n",
       "            console.warn(\"Panel: ERROR: Unable to run Panel code because Bokeh or Panel library is missing\");\n",
       "\t  } else {\n",
       "\t    console.warn(\"Panel: WARNING: Attempting to render but not all required libraries could be resolved.\")\n",
       "\t    embed_document(root)\n",
       "\t  }\n",
       "        }\n",
       "      }\n",
       "    }, 25, root)\n",
       "  }\n",
       "})(window);</script>"
      ],
      "text/plain": [
       ":NdOverlay   [Variable]\n",
       "   :Curve   [Local Timestamp]   (value)"
      ]
     },
     "execution_count": 10,
     "metadata": {
      "application/vnd.holoviews_exec.v0+json": {
       "id": "p1004"
      }
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import holoviews as hv\n",
    "\n",
    "hv.extension('bokeh')\n",
    "\n",
    "df.plot(x='Local Timestamp')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5a9d4a3",
   "metadata": {},
   "source": [
    "## Display last trades between the step"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "71dd4f1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from hftbacktest import BUY_EVENT\n",
    "\n",
    "@njit\n",
    "def print_trades(hbt):\n",
    "    while hbt.elapse(60 * 1e9) == 0:\n",
    "        print('-------------------------------------------------------------------------------')\n",
    "        print('current_timestamp:', hbt.current_timestamp)\n",
    "\n",
    "        # Gets the last trades occurring in the market, not the trades of our orders.\n",
    "        last_trades = hbt.last_trades(0)\n",
    "        \n",
    "        num = 0\n",
    "        for last_trade in last_trades:\n",
    "            if num > 10:\n",
    "                print('...')\n",
    "                break\n",
    "            print(\n",
    "                'exch_timestamp:',\n",
    "                last_trade.exch_ts,\n",
    "                'buy' if (last_trade.ev & BUY_EVENT) == BUY_EVENT else 'sell',\n",
    "                last_trade.qty,\n",
    "                '@',\n",
    "                last_trade.px\n",
    "            )\n",
    "            num += 1\n",
    "\n",
    "        # To prevent accumulating all last trades, which may cause a slowdown,\n",
    "        # clear_last_trades needs to be called.\n",
    "        # After this, accessing `last_trades` will cause a crash.\n",
    "        hbt.clear_last_trades(0)\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "0d37656a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-------------------------------------------------------------------------------\n",
      "current_timestamp: 1723161661500000000\n",
      "exch_timestamp: 1723161602372000000 buy 0.489 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.198 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.006 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.002 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.003 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.011 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.238 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.007 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.005 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.003 @ 61659.8\n",
      "exch_timestamp: 1723161602372000000 buy 0.002 @ 61659.8\n",
      "...\n",
      "-------------------------------------------------------------------------------\n",
      "current_timestamp: 1723161721500000000\n",
      "exch_timestamp: 1723161661697000000 sell 0.002 @ 61594.1\n",
      "exch_timestamp: 1723161661724000000 sell 0.002 @ 61594.1\n",
      "exch_timestamp: 1723161661751000000 buy 0.135 @ 61594.2\n",
      "exch_timestamp: 1723161661806000000 sell 1.328 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.002 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.002 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.002 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.006 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.32 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 0.032 @ 61594.1\n",
      "exch_timestamp: 1723161661806000000 sell 1.208 @ 61594.1\n",
      "...\n",
      "-------------------------------------------------------------------------------\n",
      "current_timestamp: 1723161781500000000\n",
      "exch_timestamp: 1723161721541000000 sell 0.002 @ 61576.5\n",
      "exch_timestamp: 1723161721574000000 buy 0.012 @ 61576.6\n",
      "exch_timestamp: 1723161721578000000 sell 0.003 @ 61576.5\n",
      "exch_timestamp: 1723161721583000000 buy 0.275 @ 61576.6\n",
      "exch_timestamp: 1723161721583000000 buy 0.469 @ 61576.6\n",
      "exch_timestamp: 1723161721585000000 buy 0.095 @ 61576.6\n",
      "exch_timestamp: 1723161721585000000 buy 0.102 @ 61576.6\n",
      "exch_timestamp: 1723161721585000000 buy 0.197 @ 61576.6\n",
      "exch_timestamp: 1723161721586000000 buy 0.13 @ 61576.6\n",
      "exch_timestamp: 1723161721587000000 buy 0.425 @ 61576.6\n",
      "exch_timestamp: 1723161721587000000 buy 0.324 @ 61576.6\n",
      "...\n",
      "-------------------------------------------------------------------------------\n",
      "current_timestamp: 1723161841500000000\n",
      "exch_timestamp: 1723161781628000000 sell 0.026 @ 61629.6\n",
      "exch_timestamp: 1723161781727000000 buy 0.011 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.05 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.006 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.002 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.007 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.002 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.075 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.065 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.247 @ 61629.7\n",
      "exch_timestamp: 1723161781727000000 buy 0.002 @ 61629.7\n",
      "...\n",
      "-------------------------------------------------------------------------------\n",
      "current_timestamp: 1723161901500000000\n",
      "exch_timestamp: 1723161841561000000 buy 0.01 @ 61621.6\n",
      "exch_timestamp: 1723161841561000000 buy 0.006 @ 61621.6\n",
      "exch_timestamp: 1723161841561000000 buy 0.002 @ 61621.6\n",
      "exch_timestamp: 1723161841561000000 buy 0.022 @ 61621.6\n",
      "exch_timestamp: 1723161841561000000 buy 0.097 @ 61621.6\n",
      "exch_timestamp: 1723161841561000000 buy 0.024 @ 61621.6\n",
      "exch_timestamp: 1723161841564000000 buy 0.024 @ 61621.6\n",
      "exch_timestamp: 1723161841564000000 buy 0.014 @ 61621.6\n",
      "exch_timestamp: 1723161841565000000 buy 0.003 @ 61621.6\n",
      "exch_timestamp: 1723161841613000000 buy 0.002 @ 61622.5\n",
      "exch_timestamp: 1723161841613000000 buy 0.003 @ 61622.6\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "asset = (\n",
    "    BacktestAsset()\n",
    "        .data(btcusdt_20240809)\n",
    "        .initial_snapshot(btcusdt_20240808_eod)\n",
    "        .linear_asset(1.0) \n",
    "        .constant_latency(10_000_000, 10_000_000)\n",
    "        .risk_adverse_queue_model() \n",
    "        .no_partial_fill_exchange()\n",
    "        .trading_value_fee_model(0.0002, 0.0007)\n",
    "        .tick_size(0.1)\n",
    "        .lot_size(0.001)\n",
    "        # To retrieve the last trades, `last_trades_capacity` should be set.\n",
    "        .last_trades_capacity(1000)\n",
    "        .roi_lb(30000)\n",
    "        .roi_ub(90000)\n",
    ")\n",
    "\n",
    "hbt = ROIVectorMarketDepthBacktest([asset])\n",
    "\n",
    "print_trades(hbt)\n",
    "\n",
    "_ = hbt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a37694e1",
   "metadata": {},
   "source": [
    "## Rolling Volume-Weighted Average Price"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "002fa805",
   "metadata": {},
   "outputs": [],
   "source": [
    "@njit\n",
    "def rolling_vwap(hbt, out):\n",
    "    buy_amount_bin = np.zeros(100_000, np.float64)\n",
    "    buy_qty_bin = np.zeros(100_000, np.float64)\n",
    "    sell_amount_bin = np.zeros(100_000, np.float64)\n",
    "    sell_qty_bin = np.zeros(100_000, np.float64)\n",
    "    \n",
    "    idx = 0\n",
    "    last_trade_price = np.nan\n",
    "    \n",
    "    while hbt.elapse(10 * 1e9) == 0:\n",
    "        last_trades = hbt.last_trades(0)\n",
    "        \n",
    "        for last_trade in last_trades:\n",
    "            if (last_trade.ev & BUY_EVENT) == BUY_EVENT:\n",
    "                buy_amount_bin[idx] += last_trade.px * last_trade.qty\n",
    "                buy_qty_bin[idx] += last_trade.qty\n",
    "            else:\n",
    "                sell_amount_bin[idx] += last_trade.px * last_trade.qty\n",
    "                sell_qty_bin[idx] += last_trade.qty\n",
    "                \n",
    "        hbt.clear_last_trades(0)\n",
    "        idx += 1\n",
    "\n",
    "        if idx >= 1:\n",
    "            vwap10sec = np.divide(\n",
    "                buy_amount_bin[idx - 1] + sell_amount_bin[idx - 1], \n",
    "                buy_qty_bin[idx - 1] + sell_qty_bin[idx - 1]\n",
    "            )\n",
    "        else:\n",
    "            vwap10sec = np.nan\n",
    "        \n",
    "        if idx >= 6:\n",
    "            vwap1m = np.divide(\n",
    "                np.sum(buy_amount_bin[idx - 6:idx]) + np.sum(sell_amount_bin[idx - 6:idx]), \n",
    "                np.sum(buy_qty_bin[idx - 6:idx]) + np.sum(sell_qty_bin[idx - 6:idx])\n",
    "            )\n",
    "            buy_vwap1m = np.divide(np.sum(buy_amount_bin[idx - 6:idx]), np.sum(buy_qty_bin[idx - 6:idx]))\n",
    "            sell_vwap1m = np.divide(np.sum(sell_amount_bin[idx - 6:idx]), np.sum(sell_qty_bin[idx - 6:idx]))\n",
    "        else:\n",
    "            vwap1m = np.nan\n",
    "            buy_vwap1m = np.nan\n",
    "            sell_vwap1m = np.nan\n",
    "        \n",
    "        out.append((hbt.current_timestamp, vwap10sec, vwap1m, buy_vwap1m, sell_vwap1m))\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f90739a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "hbt = ROIVectorMarketDepthBacktest([asset])\n",
    "\n",
    "tup_ty = Tuple((float64, float64, float64, float64, float64))\n",
    "out = List.empty_list(tup_ty, allocated=100_000)\n",
    "\n",
    "rolling_vwap(hbt, out)\n",
    "\n",
    "_ = hbt.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "f2ab6bd3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (30, 5)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Local Timestamp</th><th>10-sec VWAP</th><th>1-min VWAP</th><th>1-min Buy VWAP</th><th>1-min Sell VWAP</th></tr><tr><td>datetime[ns]</td><td>f64</td><td>f64</td><td>f64</td><td>f64</td></tr></thead><tbody><tr><td>2024-08-09 00:00:11.500</td><td>61687.182976</td><td>NaN</td><td>NaN</td><td>NaN</td></tr><tr><td>2024-08-09 00:00:21.500</td><td>61709.337576</td><td>NaN</td><td>NaN</td><td>NaN</td></tr><tr><td>2024-08-09 00:00:31.500</td><td>61697.538054</td><td>NaN</td><td>NaN</td><td>NaN</td></tr><tr><td>2024-08-09 00:00:41.500</td><td>61663.958879</td><td>NaN</td><td>NaN</td><td>NaN</td></tr><tr><td>2024-08-09 00:00:51.500</td><td>61637.340621</td><td>NaN</td><td>NaN</td><td>NaN</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>2024-08-09 00:04:21.500</td><td>61643.009847</td><td>61624.459011</td><td>61626.495542</td><td>61622.549429</td></tr><tr><td>2024-08-09 00:04:31.500</td><td>61670.795685</td><td>61635.877251</td><td>61638.362314</td><td>61632.48854</td></tr><tr><td>2024-08-09 00:04:41.500</td><td>61643.108582</td><td>61641.846489</td><td>61648.672337</td><td>61636.032054</td></tr><tr><td>2024-08-09 00:04:51.500</td><td>61614.723569</td><td>61640.490841</td><td>61647.769844</td><td>61634.372128</td></tr><tr><td>2024-08-09 00:05:01.500</td><td>61584.697467</td><td>61637.334102</td><td>61642.209551</td><td>61632.12064</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "shape: (30, 5)\n",
       "┌─────────────────────────┬──────────────┬──────────────┬────────────────┬─────────────────┐\n",
       "│ Local Timestamp         ┆ 10-sec VWAP  ┆ 1-min VWAP   ┆ 1-min Buy VWAP ┆ 1-min Sell VWAP │\n",
       "│ ---                     ┆ ---          ┆ ---          ┆ ---            ┆ ---             │\n",
       "│ datetime[ns]            ┆ f64          ┆ f64          ┆ f64            ┆ f64             │\n",
       "╞═════════════════════════╪══════════════╪══════════════╪════════════════╪═════════════════╡\n",
       "│ 2024-08-09 00:00:11.500 ┆ 61687.182976 ┆ NaN          ┆ NaN            ┆ NaN             │\n",
       "│ 2024-08-09 00:00:21.500 ┆ 61709.337576 ┆ NaN          ┆ NaN            ┆ NaN             │\n",
       "│ 2024-08-09 00:00:31.500 ┆ 61697.538054 ┆ NaN          ┆ NaN            ┆ NaN             │\n",
       "│ 2024-08-09 00:00:41.500 ┆ 61663.958879 ┆ NaN          ┆ NaN            ┆ NaN             │\n",
       "│ 2024-08-09 00:00:51.500 ┆ 61637.340621 ┆ NaN          ┆ NaN            ┆ NaN             │\n",
       "│ …                       ┆ …            ┆ …            ┆ …              ┆ …               │\n",
       "│ 2024-08-09 00:04:21.500 ┆ 61643.009847 ┆ 61624.459011 ┆ 61626.495542   ┆ 61622.549429    │\n",
       "│ 2024-08-09 00:04:31.500 ┆ 61670.795685 ┆ 61635.877251 ┆ 61638.362314   ┆ 61632.48854     │\n",
       "│ 2024-08-09 00:04:41.500 ┆ 61643.108582 ┆ 61641.846489 ┆ 61648.672337   ┆ 61636.032054    │\n",
       "│ 2024-08-09 00:04:51.500 ┆ 61614.723569 ┆ 61640.490841 ┆ 61647.769844   ┆ 61634.372128    │\n",
       "│ 2024-08-09 00:05:01.500 ┆ 61584.697467 ┆ 61637.334102 ┆ 61642.209551   ┆ 61632.12064     │\n",
       "└─────────────────────────┴──────────────┴──────────────┴────────────────┴─────────────────┘"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pl.DataFrame(out).transpose()\n",
    "df.columns = ['Local Timestamp', '10-sec VWAP', '1-min VWAP', '1-min Buy VWAP', '1-min Sell VWAP']\n",
    "df = df.with_columns(\n",
    "    pl.from_epoch('Local Timestamp', time_unit='ns')\n",
    ")\n",
    "\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "f23d4a4e",
   "metadata": {},
   "outputs": [
    {
     "data": {},
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.holoviews_exec.v0+json": "",
      "text/html": [
       "<div id='p1122'>\n",
       "  <div id=\"b238aabb-1e37-45a7-b26a-d373a91e996d\" data-root-id=\"p1122\" style=\"display: contents;\"></div>\n",
       "</div>\n",
       "<script type=\"application/javascript\">(function(root) {\n",
       "  var docs_json = {\"d3f2ddab-1eba-44cd-a3d7-88b5cdad0fd5\":{\"version\":\"3.4.2\",\"title\":\"Bokeh Application\",\"roots\":[{\"type\":\"object\",\"name\":\"Row\",\"id\":\"p1122\",\"attributes\":{\"name\":\"Row01243\",\"tags\":[\"embedded\"],\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1125\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/css/loading.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1246\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/css/listpanel.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1123\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/bundled/theme/default.css\"}},{\"type\":\"object\",\"name\":\"ImportedStyleSheet\",\"id\":\"p1124\",\"attributes\":{\"url\":\"https://cdn.holoviz.org/panel/1.4.4/dist/bundled/theme/native.css\"}}],\"min_width\":700,\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\",\"children\":[{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1126\",\"attributes\":{\"name\":\"HSpacer01250\",\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1125\"},{\"id\":\"p1123\"},{\"id\":\"p1124\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}},{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1143\",\"attributes\":{\"width\":700,\"height\":300,\"margin\":[5,10],\"sizing_mode\":\"fixed\",\"align\":\"start\",\"x_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1127\",\"attributes\":{\"tags\":[[[\"Local Timestamp\",null]],[]],\"start\":1723161611500.0,\"end\":1723161901500.0,\"reset_start\":1723161611500.0,\"reset_end\":1723161901500.0}},\"y_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1128\",\"attributes\":{\"tags\":[[[\"value\",null]],{\"type\":\"map\",\"entries\":[[\"invert_yaxis\",false],[\"autorange\",false]]}],\"start\":61519.87934207178,\"end\":61726.56105161555,\"reset_start\":61519.87934207178,\"reset_end\":61726.56105161555}},\"x_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1153\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1154\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1146\",\"attributes\":{\"text_color\":\"black\",\"text_font_size\":\"12pt\"}},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1195\",\"attributes\":{\"name\":\"10-sec VWAP\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1186\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1187\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1188\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"0oPx2uUe7kB7zmvNqiHuQNqSvTcxIO5AXNoir/4b7kD7dl7mqhjuQJyj7RMJFe5AK6gtu74N7kATskhKIwzuQI3wcSfqEO5ATwrYsM4T7kA07Yw7fhHuQFULaFFKEO5ANhvyMl8U7kCfXEQFpRXuQIb2oCa7HO5AFzDln6Ib7kB7/9b16BnuQPIspxmxFu5ALeHn/AkX7kCT6zRaLBnuQFWqsrnJFe5AQNw1tPwW7kCOjKwWxRbuQGL9AvBmFu5AWxCtZT8Y7kAkBKtQYBnuQLbAQHbZHO5AdDyAeWMZ7kBryHkn1xXuQB8iplEWEu5A\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\",\"10-sec VWAP\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1196\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1197\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1192\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1200\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1193\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1194\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#30a2da\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1210\",\"attributes\":{\"name\":\"1-min VWAP\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1201\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1202\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1203\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4f/OJ1jN1G+5AoGAyVE4U7kBc30L0yxHuQCqmz08BEe5AHKRgxdYQ7kBlNyyNYhDuQLo8yZqAD+5ANfSaNygR7kCjIcAOxBLuQCupbJRUFe5ANnM60g8W7kBKIMu8DxjuQBPWUx0oGe5AV5CxIdYZ7kDB1UDTcRruQGVYwLdqGO5A0R736r0X7kC0dLFAQxfuQJv1SSwwF+5ATDa3GE8X7kBfvjiwDhfuQBkycRJ8GO5AN5hvFjsZ7kBkKPi0DxnuQALc9bCqGO5A\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\",\"1-min VWAP\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1211\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1212\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1207\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1214\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1208\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1209\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#fc4f30\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1224\",\"attributes\":{\"name\":\"1-min Buy VWAP\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1215\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1216\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1217\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fyXO6NimHO5AXjuqihkV7kCQh3PQSBHuQJJX3hC5EO5APZcnw/gQ7kD01fwVdhDuQLPVDCAGEO5A9eoUpU4R7kD5ZwXO1hLuQLipaLCEFe5AthX+UD4W7kCKx78UmhfuQCzRYQ5fGe5A5BGN6oga7kDoFdHvoBruQA/P7T+5GO5AQlMV4bUX7kAhL4FdhRfuQPI3zkJzF+5APh6AMZAX7kAoJHrbTxfuQMdgE5jLGO5ACNbJgxUa7kBaE5Ci+BnuQEF+pLRGGe5A\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\",\"1-min Buy VWAP\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1225\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1226\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1221\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1228\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1222\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1223\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#e5ae38\",\"line_alpha\":0.2,\"line_width\":2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1238\",\"attributes\":{\"name\":\"1-min Sell VWAP\",\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1229\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1230\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1231\"},\"data\":{\"type\":\"map\",\"entries\":[[\"Local Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"value\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4f8jC4qiUGu5Adnww6OwT7kALDS5XEhLuQAuSWAAtEe5AkD0IXb4Q7kAYdNOgVBDuQEAEcjEFD+5AWFE+JuwQ7kDLnF2AqhLuQBIk4tYUFe5Ai45D89cV7kC5Cf4boBjuQAC4pUXwGO5Amk86zDoZ7kD5jA1sPxruQMkUmlczGO5AEffx+MUX7kBteUwp+RbuQH56d9fwFu5Ap7YvbwsX7kAZvOuU0RbuQM0KHqIPGO5AyJeWBoEY7kBnH3noSxjuQG4YSdwDGO5A\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Local_Timestamp\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AMDO+EYTeUIAwD/7RhN5QgDAsP1GE3lCAMAhAEcTeUIAwJICRxN5QgDAAwVHE3lCAMB0B0cTeUIAwOUJRxN5QgDAVgxHE3lCAMDHDkcTeUIAwDgRRxN5QgDAqRNHE3lCAMAaFkcTeUIAwIsYRxN5QgDA/BpHE3lCAMBtHUcTeUIAwN4fRxN5QgDATyJHE3lCAMDAJEcTeUIAwDEnRxN5QgDAoilHE3lCAMATLEcTeUIAwIQuRxN5QgDA9TBHE3lCAMBmM0cTeUIAwNc1RxN5QgDASDhHE3lCAMC5OkcTeUIAwCo9RxN5QgDAmz9HE3lC\"},\"shape\":[30],\"dtype\":\"float64\",\"order\":\"little\"}],[\"Variable\",[\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\",\"1-min Sell VWAP\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1239\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1240\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1235\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#6d904f\",\"line_width\":2}},\"selection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1242\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#6d904f\",\"line_width\":2}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1236\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#6d904f\",\"line_alpha\":0.1,\"line_width\":2}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1237\",\"attributes\":{\"tags\":[\"apply_ranges\"],\"x\":{\"type\":\"field\",\"field\":\"Local Timestamp\"},\"y\":{\"type\":\"field\",\"field\":\"value\"},\"line_color\":\"#6d904f\",\"line_alpha\":0.2,\"line_width\":2}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1152\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1132\",\"attributes\":{\"tags\":[\"hv_created\"],\"renderers\":\"auto\",\"zoom_together\":\"none\"}},{\"type\":\"object\",\"name\":\"HoverTool\",\"id\":\"p1133\",\"attributes\":{\"tags\":[\"hv_created\"],\"renderers\":[{\"id\":\"p1195\"},{\"id\":\"p1210\"},{\"id\":\"p1224\"},{\"id\":\"p1238\"}],\"tooltips\":[[\"Variable\",\"@{Variable}\"],[\"Local Timestamp\",\"@{Local_Timestamp}{%F %T}\"],[\"value\",\"@{value}\"]],\"formatters\":{\"type\":\"map\",\"entries\":[[\"@{Local Timestamp}\",\"datetime\"],[\"@{Local_Timestamp}\",\"datetime\"]]}}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1177\"},{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1178\"},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1179\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1180\",\"attributes\":{\"syncable\":false,\"level\":\"overlay\",\"visible\":false,\"left\":{\"type\":\"number\",\"value\":\"nan\"},\"right\":{\"type\":\"number\",\"value\":\"nan\"},\"top\":{\"type\":\"number\",\"value\":\"nan\"},\"bottom\":{\"type\":\"number\",\"value\":\"nan\"},\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"top_units\":\"canvas\",\"bottom_units\":\"canvas\",\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5}}}},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1185\"}],\"active_drag\":{\"id\":\"p1178\"},\"active_scroll\":{\"id\":\"p1132\"}}},\"left\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1172\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1173\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1174\"},\"axis_label\":\"\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1175\"}}}],\"right\":[{\"type\":\"object\",\"name\":\"Legend\",\"id\":\"p1198\",\"attributes\":{\"location\":[0,0],\"title\":\"Variable\",\"click_policy\":\"mute\",\"items\":[{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1199\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"10-sec VWAP\"},\"renderers\":[{\"id\":\"p1195\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1213\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"1-min VWAP\"},\"renderers\":[{\"id\":\"p1210\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1227\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"1-min Buy VWAP\"},\"renderers\":[{\"id\":\"p1224\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1241\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"1-min Sell VWAP\"},\"renderers\":[{\"id\":\"p1238\"}]}}]}}],\"below\":[{\"type\":\"object\",\"name\":\"DatetimeAxis\",\"id\":\"p1155\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"DatetimeTicker\",\"id\":\"p1156\",\"attributes\":{\"num_minor_ticks\":5,\"tickers\":[{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1157\",\"attributes\":{\"num_minor_ticks\":0,\"mantissas\":[1,2,5],\"max_interval\":500.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1158\",\"attributes\":{\"num_minor_ticks\":0,\"base\":60,\"mantissas\":[1,2,5,10,15,20,30],\"min_interval\":1000.0,\"max_interval\":1800000.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1159\",\"attributes\":{\"num_minor_ticks\":0,\"base\":24,\"mantissas\":[1,2,4,6,8,12],\"min_interval\":3600000.0,\"max_interval\":43200000.0}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1160\",\"attributes\":{\"days\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1161\",\"attributes\":{\"days\":[1,4,7,10,13,16,19,22,25,28]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1162\",\"attributes\":{\"days\":[1,8,15,22]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1163\",\"attributes\":{\"days\":[1,15]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1164\",\"attributes\":{\"months\":[0,1,2,3,4,5,6,7,8,9,10,11]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1165\",\"attributes\":{\"months\":[0,2,4,6,8,10]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1166\",\"attributes\":{\"months\":[0,4,8]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1167\",\"attributes\":{\"months\":[0,6]}},{\"type\":\"object\",\"name\":\"YearsTicker\",\"id\":\"p1168\"}]}},\"formatter\":{\"type\":\"object\",\"name\":\"DatetimeTickFormatter\",\"id\":\"p1169\"},\"axis_label\":\"Local Timestamp\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1170\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1171\",\"attributes\":{\"axis\":{\"id\":\"p1155\"},\"grid_line_color\":null}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1176\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1172\"},\"grid_line_color\":null}}],\"min_border_top\":10,\"min_border_bottom\":10,\"min_border_left\":10,\"min_border_right\":10,\"output_backend\":\"webgl\"}},{\"type\":\"object\",\"name\":\"Spacer\",\"id\":\"p1244\",\"attributes\":{\"name\":\"HSpacer01251\",\"stylesheets\":[\"\\n:host(.pn-loading):before, .pn-loading:before {\\n  background-color: #c3c3c3;\\n  mask-size: auto calc(min(50%, 400px));\\n  -webkit-mask-size: auto calc(min(50%, 400px));\\n}\",{\"id\":\"p1125\"},{\"id\":\"p1123\"},{\"id\":\"p1124\"}],\"margin\":0,\"sizing_mode\":\"stretch_width\",\"align\":\"start\"}}]}}],\"defs\":[{\"type\":\"model\",\"name\":\"ReactiveHTML1\"},{\"type\":\"model\",\"name\":\"FlexBox1\",\"properties\":[{\"name\":\"align_content\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"align_items\",\"kind\":\"Any\",\"default\":\"flex-start\"},{\"name\":\"flex_direction\",\"kind\":\"Any\",\"default\":\"row\"},{\"name\":\"flex_wrap\",\"kind\":\"Any\",\"default\":\"wrap\"},{\"name\":\"gap\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"justify_content\",\"kind\":\"Any\",\"default\":\"flex-start\"}]},{\"type\":\"model\",\"name\":\"FloatPanel1\",\"properties\":[{\"name\":\"config\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"contained\",\"kind\":\"Any\",\"default\":true},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"right-top\"},{\"name\":\"offsetx\",\"kind\":\"Any\",\"default\":null},{\"name\":\"offsety\",\"kind\":\"Any\",\"default\":null},{\"name\":\"theme\",\"kind\":\"Any\",\"default\":\"primary\"},{\"name\":\"status\",\"kind\":\"Any\",\"default\":\"normalized\"}]},{\"type\":\"model\",\"name\":\"GridStack1\",\"properties\":[{\"name\":\"mode\",\"kind\":\"Any\",\"default\":\"warn\"},{\"name\":\"ncols\",\"kind\":\"Any\",\"default\":null},{\"name\":\"nrows\",\"kind\":\"Any\",\"default\":null},{\"name\":\"allow_resize\",\"kind\":\"Any\",\"default\":true},{\"name\":\"allow_drag\",\"kind\":\"Any\",\"default\":true},{\"name\":\"state\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"drag1\",\"properties\":[{\"name\":\"slider_width\",\"kind\":\"Any\",\"default\":5},{\"name\":\"slider_color\",\"kind\":\"Any\",\"default\":\"black\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":50}]},{\"type\":\"model\",\"name\":\"click1\",\"properties\":[{\"name\":\"terminal_output\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"debug_name\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"clears\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"FastWrapper1\",\"properties\":[{\"name\":\"object\",\"kind\":\"Any\",\"default\":null},{\"name\":\"style\",\"kind\":\"Any\",\"default\":null}]},{\"type\":\"model\",\"name\":\"NotificationAreaBase1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"NotificationArea1\",\"properties\":[{\"name\":\"js_events\",\"kind\":\"Any\",\"default\":{\"type\":\"map\"}},{\"name\":\"notifications\",\"kind\":\"Any\",\"default\":[]},{\"name\":\"position\",\"kind\":\"Any\",\"default\":\"bottom-right\"},{\"name\":\"_clear\",\"kind\":\"Any\",\"default\":0},{\"name\":\"types\",\"kind\":\"Any\",\"default\":[{\"type\":\"map\",\"entries\":[[\"type\",\"warning\"],[\"background\",\"#ffc107\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-exclamation-triangle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]},{\"type\":\"map\",\"entries\":[[\"type\",\"info\"],[\"background\",\"#007bff\"],[\"icon\",{\"type\":\"map\",\"entries\":[[\"className\",\"fas fa-info-circle\"],[\"tagName\",\"i\"],[\"color\",\"white\"]]}]]}]}]},{\"type\":\"model\",\"name\":\"Notification\",\"properties\":[{\"name\":\"background\",\"kind\":\"Any\",\"default\":null},{\"name\":\"duration\",\"kind\":\"Any\",\"default\":3000},{\"name\":\"icon\",\"kind\":\"Any\",\"default\":null},{\"name\":\"message\",\"kind\":\"Any\",\"default\":\"\"},{\"name\":\"notification_type\",\"kind\":\"Any\",\"default\":null},{\"name\":\"_destroyed\",\"kind\":\"Any\",\"default\":false}]},{\"type\":\"model\",\"name\":\"TemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"BootstrapTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"TemplateEditor1\",\"properties\":[{\"name\":\"layout\",\"kind\":\"Any\",\"default\":[]}]},{\"type\":\"model\",\"name\":\"MaterialTemplateActions1\",\"properties\":[{\"name\":\"open_modal\",\"kind\":\"Any\",\"default\":0},{\"name\":\"close_modal\",\"kind\":\"Any\",\"default\":0}]},{\"type\":\"model\",\"name\":\"copy_to_clipboard1\",\"properties\":[{\"name\":\"fill\",\"kind\":\"Any\",\"default\":\"none\"},{\"name\":\"value\",\"kind\":\"Any\",\"default\":null}]}]}};\n",
       "  var render_items = [{\"docid\":\"d3f2ddab-1eba-44cd-a3d7-88b5cdad0fd5\",\"roots\":{\"p1122\":\"b238aabb-1e37-45a7-b26a-d373a91e996d\"},\"root_ids\":[\"p1122\"]}];\n",
       "  var docs = Object.values(docs_json)\n",
       "  if (!docs) {\n",
       "    return\n",
       "  }\n",
       "  const py_version = docs[0].version.replace('rc', '-rc.').replace('.dev', '-dev.')\n",
       "  async function embed_document(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    await Bokeh.embed.embed_items_notebook(docs_json, render_items);\n",
       "    for (const render_item of render_items) {\n",
       "      for (const root_id of render_item.root_ids) {\n",
       "\tconst id_el = document.getElementById(root_id)\n",
       "\tif (id_el.children.length && id_el.children[0].hasAttribute('data-root-id')) {\n",
       "\t  const root_el = id_el.children[0]\n",
       "\t  root_el.id = root_el.id + '-rendered'\n",
       "\t  for (const child of root_el.children) {\n",
       "            // Ensure JupyterLab does not capture keyboard shortcuts\n",
       "            // see: https://jupyterlab.readthedocs.io/en/4.1.x/extension/notebook.html#keyboard-interaction-model\n",
       "\t    child.setAttribute('data-lm-suppress-shortcuts', 'true')\n",
       "\t  }\n",
       "\t}\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "  function get_bokeh(root) {\n",
       "    if (root.Bokeh === undefined) {\n",
       "      return null\n",
       "    } else if (root.Bokeh.version !== py_version) {\n",
       "      if (root.Bokeh.versions === undefined || !root.Bokeh.versions.has(py_version)) {\n",
       "\treturn null\n",
       "      }\n",
       "      return root.Bokeh.versions.get(py_version);\n",
       "    } else if (root.Bokeh.version === py_version) {\n",
       "      return root.Bokeh\n",
       "    }\n",
       "    return null\n",
       "  }\n",
       "  function is_loaded(root) {\n",
       "    var Bokeh = get_bokeh(root)\n",
       "    return (Bokeh != null && Bokeh.Panel !== undefined)\n",
       "  }\n",
       "  if (is_loaded(root)) {\n",
       "    embed_document(root);\n",
       "  } else {\n",
       "    var attempts = 0;\n",
       "    var timer = setInterval(function(root) {\n",
       "      if (is_loaded(root)) {\n",
       "        clearInterval(timer);\n",
       "        embed_document(root);\n",
       "      } else if (document.readyState == \"complete\") {\n",
       "        attempts++;\n",
       "        if (attempts > 200) {\n",
       "          clearInterval(timer);\n",
       "\t  var Bokeh = get_bokeh(root)\n",
       "\t  if (Bokeh == null || Bokeh.Panel == null) {\n",
       "            console.warn(\"Panel: ERROR: Unable to run Panel code because Bokeh or Panel library is missing\");\n",
       "\t  } else {\n",
       "\t    console.warn(\"Panel: WARNING: Attempting to render but not all required libraries could be resolved.\")\n",
       "\t    embed_document(root)\n",
       "\t  }\n",
       "        }\n",
       "      }\n",
       "    }, 25, root)\n",
       "  }\n",
       "})(window);</script>"
      ],
      "text/plain": [
       ":NdOverlay   [Variable]\n",
       "   :Curve   [Local Timestamp]   (value)"
      ]
     },
     "execution_count": 16,
     "metadata": {
      "application/vnd.holoviews_exec.v0+json": {
       "id": "p1122"
      }
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.plot(x='Local Timestamp')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
